diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 0b9a060fb5..194e84b8ea 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -12,6 +12,8 @@ var cmdline_buffer: [4096]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer); pub fn main() void { + if (builtin.zig_backend == .stage2_riscv64) return mainExtraSimple() catch @panic("test failure"); + if (builtin.zig_backend == .stage2_aarch64) { return mainSimple() catch @panic("test failure"); } @@ -247,3 +249,19 @@ pub fn mainSimple() anyerror!void { if (failed != 0) std.process.exit(1); } } + +pub fn mainExtraSimple() !void { + var fail_count: u8 = 0; + + for (builtin.test_functions) |test_fn| { + test_fn.func() catch |err| { + if (err != error.SkipZigTest) { + fail_count += 1; + continue; + } + continue; + }; + } + + if (fail_count != 0) std.process.exit(1); +} diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 6354cb261a..3026911d3f 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -766,7 +766,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr builtin.zig_backend == .stage2_aarch64 or builtin.zig_backend == .stage2_x86 or (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or - builtin.zig_backend == .stage2_riscv64 or builtin.zig_backend == .stage2_sparc64 or builtin.zig_backend == .stage2_spirv64) { @@ -774,6 +773,19 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr @breakpoint(); } } + + if (builtin.zig_backend == .stage2_riscv64) { + asm volatile ("ecall" + : + : [number] "{a7}" (64), + [arg1] "{a0}" (1), + [arg2] "{a1}" (@intFromPtr(msg.ptr)), + [arg3] "{a2}" (msg.len), + : "memory" + ); + std.posix.exit(127); + } + switch (builtin.os.tag) { .freestanding => { while (true) { diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index a0f5a7f0a8..242408f6b2 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -1236,15 +1236,7 @@ pub const DwarfInfo = struct { const opcode_base = try fbr.readByte(); - const standard_opcode_lengths = try allocator.alloc(u8, opcode_base - 1); - defer allocator.free(standard_opcode_lengths); - - { - var i: usize = 0; - while (i < opcode_base - 1) : (i += 1) { - standard_opcode_lengths[i] = try fbr.readByte(); - } - } + const standard_opcode_lengths = try fbr.readBytes(opcode_base - 1); var include_directories = std.ArrayList(FileEntry).init(allocator); defer include_directories.deinit(); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index fe54a0ce74..aff9532ecb 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -638,6 +638,8 @@ test lessThan { const backend_can_use_eql_bytes = switch (builtin.zig_backend) { // The SPIR-V backend does not support the optimized path yet. .stage2_spirv64 => false, + // The RISC-V does not support vectors. + .stage2_riscv64 => false, else => true, }; diff --git a/lib/std/start.zig b/lib/std/start.zig index 24674614e2..ff97e3c8ae 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -20,10 +20,10 @@ pub const simplified_logic = builtin.zig_backend == .stage2_x86 or builtin.zig_backend == .stage2_aarch64 or builtin.zig_backend == .stage2_arm or - builtin.zig_backend == .stage2_riscv64 or builtin.zig_backend == .stage2_sparc64 or builtin.cpu.arch == .spirv32 or - builtin.cpu.arch == .spirv64; + builtin.cpu.arch == .spirv64 or + builtin.zig_backend == .stage2_riscv64; comptime { // No matter what, we import the root file, so that any export, test, comptime @@ -43,6 +43,10 @@ comptime { } else if (builtin.os.tag == .opencl) { if (@hasDecl(root, "main")) @export(spirvMain2, .{ .name = "main" }); + } else if (native_arch.isRISCV()) { + if (!@hasDecl(root, "_start")) { + @export(riscv_start, .{ .name = "_start" }); + } } else { if (!@hasDecl(root, "_start")) { @export(_start2, .{ .name = "_start" }); @@ -151,14 +155,6 @@ fn exit2(code: usize) noreturn { : "memory", "cc" ); }, - .riscv64 => { - asm volatile ("ecall" - : - : [number] "{a7}" (94), - [arg1] "{a0}" (0), - : "rcx", "r11", "memory" - ); - }, .sparc64 => { asm volatile ("ta 0x6d" : @@ -212,6 +208,23 @@ fn wasi_start() callconv(.C) void { } } +fn riscv_start() callconv(.C) noreturn { + std.process.exit(switch (@typeInfo(@typeInfo(@TypeOf(root.main)).Fn.return_type.?)) { + .NoReturn => root.main(), + .Void => ret: { + root.main(); + break :ret 0; + }, + .Int => |info| ret: { + if (info.bits != 8 or info.signedness == .signed) { + @compileError(bad_main_ret); + } + break :ret root.main(); + }, + else => @compileError("expected return type of main to be 'void', 'noreturn', 'u8'"), + }); +} + fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize { uefi.handle = handle; uefi.system_table = system_table; diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 2d97580a22..4e895ef3a7 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -22,7 +22,7 @@ pub var base_allocator_instance = std.heap.FixedBufferAllocator.init(""); pub var log_level = std.log.Level.warn; // Disable printing in tests for simple backends. -pub const backend_can_print = builtin.zig_backend != .stage2_spirv64; +pub const backend_can_print = !(builtin.zig_backend == .stage2_spirv64 or builtin.zig_backend == .stage2_riscv64); fn print(comptime fmt: []const u8, args: anytype) void { if (@inComptime()) { diff --git a/src/Sema.zig b/src/Sema.zig index 86d3378aee..37fdf0adb5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10499,9 +10499,10 @@ fn intCast( const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty); const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar); const dest_max = Air.internedToRef(dest_max_val.toIntern()); - const diff = try block.addBinOp(.sub_wrap, dest_max, operand); if (actual_info.signedness == .signed) { + const diff = try block.addBinOp(.sub_wrap, dest_max, operand); + // Reinterpret the sign-bit as part of the value. This will make // negative differences (`operand` > `dest_max`) appear too big. const unsigned_scalar_operand_ty = try mod.intType(.unsigned, actual_bits); @@ -10542,7 +10543,7 @@ fn intCast( try sema.addSafetyCheck(block, src, ok, .cast_truncated_data); } else { const ok = if (is_vector) ok: { - const is_in_range = try block.addCmpVector(diff, dest_max, .lte); + const is_in_range = try block.addCmpVector(operand, dest_max, .lte); const all_in_range = try block.addInst(.{ .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce, .data = .{ .reduce = .{ @@ -10552,7 +10553,7 @@ fn intCast( }); break :ok all_in_range; } else ok: { - const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); + const is_in_range = try block.addBinOp(.cmp_lte, operand, dest_max); break :ok is_in_range; }; try sema.addSafetyCheck(block, src, ok, .cast_truncated_data); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 5abe3afcfd..762251bc44 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -11,6 +11,7 @@ const Type = @import("../../type.zig").Type; const Value = @import("../../Value.zig"); const link = @import("../../link.zig"); const Module = @import("../../Module.zig"); +const Package = @import("../../Package.zig"); const InternPool = @import("../../InternPool.zig"); const Compilation = @import("../../Compilation.zig"); const ErrorMsg = Module.ErrorMsg; @@ -19,7 +20,8 @@ const Allocator = mem.Allocator; const trace = @import("../../tracy.zig").trace; const DW = std.dwarf; const leb128 = std.leb; -const log = std.log.scoped(.codegen); +const log = std.log.scoped(.riscv_codegen); +const tracking_log = std.log.scoped(.tracking); const build_options = @import("build_options"); const codegen = @import("../../codegen.zig"); const Alignment = InternPool.Alignment; @@ -31,16 +33,31 @@ const DebugInfoOutput = codegen.DebugInfoOutput; const bits = @import("bits.zig"); const abi = @import("abi.zig"); const Register = bits.Register; +const Immediate = bits.Immediate; +const Memory = bits.Memory; +const FrameIndex = bits.FrameIndex; const RegisterManager = abi.RegisterManager; const RegisterLock = RegisterManager.RegisterLock; -const Instruction = abi.Instruction; const callee_preserved_regs = abi.callee_preserved_regs; +/// General Purpose const gp = abi.RegisterClass.gp; +/// Function Args +const fa = abi.RegisterClass.fa; +/// Function Returns +const fr = abi.RegisterClass.fr; +/// Temporary Use +const tp = abi.RegisterClass.tp; const InnerError = CodeGenError || error{OutOfRegisters}; +const RegisterView = enum(u1) { + caller, + callee, +}; + gpa: Allocator, air: Air, +mod: *Package.Module, liveness: Liveness, bin_file: *link.File, target: *const std.Target, @@ -49,11 +66,10 @@ code: *std.ArrayList(u8), debug_output: DebugInfoOutput, err_msg: ?*ErrorMsg, args: []MCValue, -ret_mcv: MCValue, +ret_mcv: InstTracking, fn_type: Type, arg_index: usize, src_loc: Module.SrcLoc, -stack_align: Alignment, /// MIR Instructions mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, @@ -64,6 +80,8 @@ mir_extra: std.ArrayListUnmanaged(u32) = .{}, end_di_line: u32, end_di_column: u32, +scope_generation: u32, + /// The value is an offset into the `Function` `code` from the beginning. /// To perform the reloc, write 32-bit signed little-endian integer /// which is a relative jump, based on the address following the reloc. @@ -80,22 +98,24 @@ branch_stack: *std.ArrayList(Branch), // Key is the block instruction blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, - register_manager: RegisterManager = .{}, -/// Maps offset to what is stored there. -stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, -/// Offset from the stack base, representing the end of the stack frame. -max_end_stack: u32 = 0, -/// Represents the current end stack offset. If there is no existing slot -/// to place a new stack allocation, it goes here, and then bumps `max_end_stack`. -next_stack_offset: u32 = 0, +const_tracking: ConstTrackingMap = .{}, +inst_tracking: InstTrackingMap = .{}, + +frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, +free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{}, +frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, /// Debug field, used to find bugs in the compiler. air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; +const SymbolOffset = struct { sym: u32, off: i32 = 0 }; +const RegisterOffset = struct { reg: Register, off: i32 = 0 }; +pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; + const MCValue = union(enum) { /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. /// TODO Look into deleting this tag and using `dead` instead, since every use @@ -104,26 +124,43 @@ const MCValue = union(enum) { /// Control flow will not allow this value to be observed. unreach, /// No more references to this value remain. - dead, + /// The payload is the value of scope_generation at the point where the death occurred + dead: u32, /// The value is undefined. undef, /// A pointer-sized integer that fits in a register. /// If the type is a pointer, this is the pointer address in virtual address space. immediate: u64, + /// The value doesn't exist in memory yet. + load_symbol: SymbolOffset, + /// The address of the memory location not-yet-allocated by the linker. + lea_symbol: SymbolOffset, /// The value is in a target-specific register. register: Register, + /// The value is split across two registers + register_pair: [2]Register, /// The value is in memory at a hard-coded address. /// If the type is a pointer, it means the pointer address is at this memory location. memory: u64, - /// The value is one of the stack variables. - /// If the type is a pointer, it means the pointer address is in the stack at this offset. - stack_offset: u32, - /// The value is a pointer to one of the stack variables (payload is stack offset). - ptr_stack_offset: u32, + /// The value stored at an offset from a frame index + /// Payload is a frame address. + load_frame: FrameAddr, + /// The address of an offset from a frame index + /// Payload is a frame address. + lea_frame: FrameAddr, + air_ref: Air.Inst.Ref, + /// The value is in memory at a constant offset from the address in a register. + indirect: RegisterOffset, + /// The value is a constant offset from the value in a register. + register_offset: RegisterOffset, + /// This indicates that we have already allocated a frame index for this instruction, + /// but it has not been spilled there yet in the current control flow. + /// Payload is a frame index. + reserved_frame: FrameIndex, fn isMemory(mcv: MCValue) bool { return switch (mcv) { - .memory, .stack_offset => true, + .memory, .indirect, .load_frame => true, else => false, }; } @@ -143,15 +180,116 @@ const MCValue = union(enum) { .immediate, .memory, - .ptr_stack_offset, + .lea_frame, .undef, + .lea_symbol, + .air_ref, + .reserved_frame, => false, .register, - .stack_offset, + .register_pair, + .register_offset, + .load_frame, + .load_symbol, + .indirect, => true, }; } + + fn address(mcv: MCValue) MCValue { + return switch (mcv) { + .none, + .unreach, + .dead, + .immediate, + .lea_frame, + .register_offset, + .register_pair, + .register, + .undef, + .air_ref, + .lea_symbol, + .reserved_frame, + => unreachable, // not in memory + + .load_symbol => |sym_off| .{ .lea_symbol = sym_off }, + .memory => |addr| .{ .immediate = addr }, + .load_frame => |off| .{ .lea_frame = off }, + .indirect => |reg_off| switch (reg_off.off) { + 0 => .{ .register = reg_off.reg }, + else => .{ .register_offset = reg_off }, + }, + }; + } + + fn deref(mcv: MCValue) MCValue { + return switch (mcv) { + .none, + .unreach, + .dead, + .memory, + .indirect, + .undef, + .air_ref, + .load_frame, + .register_pair, + .load_symbol, + .reserved_frame, + => unreachable, // not a pointer + + .immediate => |addr| .{ .memory = addr }, + .lea_frame => |off| .{ .load_frame = off }, + .register => |reg| .{ .indirect = .{ .reg = reg } }, + .register_offset => |reg_off| .{ .indirect = reg_off }, + .lea_symbol => |sym_off| .{ .load_symbol = sym_off }, + }; + } + + fn offset(mcv: MCValue, off: i32) MCValue { + return switch (mcv) { + .none, + .unreach, + .dead, + .undef, + .air_ref, + .reserved_frame, + => unreachable, // not valid + .register_pair, + .memory, + .indirect, + .load_frame, + .load_symbol, + .lea_symbol, + => switch (off) { + 0 => mcv, + else => unreachable, // not offsettable + }, + .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) }, + .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } }, + .register_offset => |reg_off| .{ .register_offset = .{ .reg = reg_off.reg, .off = reg_off.off + off } }, + .lea_frame => |frame_addr| .{ + .lea_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off }, + }, + }; + } + + fn getReg(mcv: MCValue) ?Register { + return switch (mcv) { + .register => |reg| reg, + .register_offset, .indirect => |ro| ro.reg, + else => null, + }; + } + + fn getRegs(mcv: *const MCValue) []const Register { + return switch (mcv.*) { + .register => |*reg| @as(*const [1]Register, reg), + .register_pair => |*regs| regs, + .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg), + else => &.{}, + }; + } }; const Branch = struct { @@ -163,60 +301,403 @@ const Branch = struct { } }; +const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking); +const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking); +const InstTracking = struct { + long: MCValue, + short: MCValue, + + fn init(result: MCValue) InstTracking { + return .{ .long = switch (result) { + .none, + .unreach, + .undef, + .immediate, + .memory, + .load_frame, + .lea_frame, + .load_symbol, + .lea_symbol, + => result, + .dead, + .reserved_frame, + .air_ref, + => unreachable, + .register, + .register_pair, + .register_offset, + .indirect, + => .none, + }, .short = result }; + } + + fn getReg(self: InstTracking) ?Register { + return self.short.getReg(); + } + + fn getRegs(self: *const InstTracking) []const Register { + return self.short.getRegs(); + } + + fn spill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { + if (std.meta.eql(self.long, self.short)) return; // Already spilled + // Allocate or reuse frame index + switch (self.long) { + .none => self.long = try function.allocRegOrMem(inst, false), + .load_frame => {}, + .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, + else => unreachable, + } + tracking_log.debug("spill %{d} from {} to {}", .{ inst, self.short, self.long }); + try function.genCopy(function.typeOfIndex(inst), self.long, self.short); + } + + fn reuseFrame(self: *InstTracking) void { + switch (self.long) { + .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, + else => {}, + } + self.short = switch (self.long) { + .none, + .unreach, + .undef, + .immediate, + .memory, + .load_frame, + .lea_frame, + .load_symbol, + .lea_symbol, + => self.long, + .dead, + .register, + .register_pair, + .register_offset, + .indirect, + .reserved_frame, + .air_ref, + => unreachable, + }; + } + + fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { + try function.freeValue(self.short); + self.reuseFrame(); + tracking_log.debug("%{d} => {} (spilled)", .{ inst, self.* }); + } + + fn verifyMaterialize(self: InstTracking, target: InstTracking) void { + switch (self.long) { + .none, + .unreach, + .undef, + .immediate, + .memory, + .lea_frame, + .load_symbol, + .lea_symbol, + => assert(std.meta.eql(self.long, target.long)), + .load_frame, + .reserved_frame, + => switch (target.long) { + .none, + .load_frame, + .reserved_frame, + => {}, + else => unreachable, + }, + .dead, + .register, + .register_pair, + .register_offset, + .indirect, + .air_ref, + => unreachable, + } + } + + fn materialize( + self: *InstTracking, + function: *Self, + inst: Air.Inst.Index, + target: InstTracking, + ) !void { + self.verifyMaterialize(target); + try self.materializeUnsafe(function, inst, target); + } + + fn materializeUnsafe( + self: InstTracking, + function: *Self, + inst: Air.Inst.Index, + target: InstTracking, + ) !void { + const ty = function.typeOfIndex(inst); + if ((self.long == .none or self.long == .reserved_frame) and target.long == .load_frame) + try function.genCopy(ty, target.long, self.short); + try function.genCopy(ty, target.short, self.short); + } + + fn trackMaterialize(self: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void { + self.verifyMaterialize(target); + // Don't clobber reserved frame indices + self.long = if (target.long == .none) switch (self.long) { + .load_frame => |addr| .{ .reserved_frame = addr.index }, + .reserved_frame => self.long, + else => target.long, + } else target.long; + self.short = target.short; + tracking_log.debug("%{d} => {} (materialize)", .{ inst, self.* }); + } + + fn resurrect(self: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void { + switch (self.short) { + .dead => |die_generation| if (die_generation >= scope_generation) { + self.reuseFrame(); + tracking_log.debug("%{d} => {} (resurrect)", .{ inst, self.* }); + }, + else => {}, + } + } + + fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void { + if (self.short == .dead) return; + try function.freeValue(self.short); + self.short = .{ .dead = function.scope_generation }; + tracking_log.debug("%{d} => {} (death)", .{ inst, self.* }); + } + + fn reuse( + self: *InstTracking, + function: *Self, + new_inst: ?Air.Inst.Index, + old_inst: Air.Inst.Index, + ) void { + self.short = .{ .dead = function.scope_generation }; + if (new_inst) |inst| + tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, self.*, old_inst }) + else + tracking_log.debug("tmp => {} (reuse %{d})", .{ self.*, old_inst }); + } + + fn liveOut(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void { + for (self.getRegs()) |reg| { + if (function.register_manager.isRegFree(reg)) { + tracking_log.debug("%{d} => {} (live-out)", .{ inst, self.* }); + continue; + } + + const index = RegisterManager.indexOfRegIntoTracked(reg).?; + const tracked_inst = function.register_manager.registers[index]; + const tracking = function.getResolvedInstValue(tracked_inst); + + // Disable death. + var found_reg = false; + var remaining_reg: Register = .zero; + for (tracking.getRegs()) |tracked_reg| if (tracked_reg.id() == reg.id()) { + assert(!found_reg); + found_reg = true; + } else { + assert(remaining_reg == .zero); + remaining_reg = tracked_reg; + }; + assert(found_reg); + tracking.short = switch (remaining_reg) { + .zero => .{ .dead = function.scope_generation }, + else => .{ .register = remaining_reg }, + }; + + // Perform side-effects of freeValue manually. + function.register_manager.freeReg(reg); + + tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, self.*, tracked_inst }); + } + } + + pub fn format( + self: InstTracking, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) @TypeOf(writer).Error!void { + if (!std.meta.eql(self.long, self.short)) try writer.print("|{}| ", .{self.long}); + try writer.print("{}", .{self.short}); + } +}; + +const FrameAlloc = struct { + abi_size: u31, + spill_pad: u3, + abi_align: Alignment, + ref_count: u16, + + fn init(alloc_abi: struct { size: u64, pad: u3 = 0, alignment: Alignment }) FrameAlloc { + return .{ + .abi_size = @intCast(alloc_abi.size), + .spill_pad = alloc_abi.pad, + .abi_align = alloc_abi.alignment, + .ref_count = 0, + }; + } + fn initType(ty: Type, zcu: *Module) FrameAlloc { + return init(.{ + .size = ty.abiSize(zcu), + .alignment = ty.abiAlignment(zcu), + }); + } + fn initSpill(ty: Type, zcu: *Module) FrameAlloc { + const abi_size = ty.abiSize(zcu); + const spill_size = if (abi_size < 8) + math.ceilPowerOfTwoAssert(u64, abi_size) + else + std.mem.alignForward(u64, abi_size, 8); + return init(.{ + .size = spill_size, + .pad = @intCast(spill_size - abi_size), + .alignment = ty.abiAlignment(zcu).maxStrict( + Alignment.fromNonzeroByteUnits(@min(spill_size, 8)), + ), + }); + } +}; + const StackAllocation = struct { - inst: Air.Inst.Index, - /// TODO do we need size? should be determined by inst.ty.abiSize() + inst: ?Air.Inst.Index, + /// TODO: make the size inferred from the bits of the inst size: u32, }; const BlockData = struct { - relocs: std.ArrayListUnmanaged(Reloc), - /// The first break instruction encounters `null` here and chooses a - /// machine code value for the block result, populating this field. - /// Following break instructions encounter that value and use it for - /// the location to store their block results. - mcv: MCValue, + relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}, + state: State, + + fn deinit(self: *BlockData, gpa: Allocator) void { + self.relocs.deinit(gpa); + self.* = undefined; + } }; -const Reloc = union(enum) { - /// The value is an offset into the `Function` `code` from the beginning. - /// To perform the reloc, write 32-bit signed little-endian integer - /// which is a relative jump, based on the address following the reloc. - rel32: usize, - /// A branch in the ARM instruction set - arm_branch: struct { - pos: usize, - cond: @import("../arm/bits.zig").Condition, - }, +const State = struct { + registers: RegisterManager.TrackedRegisters, + reg_tracking: [RegisterManager.RegisterBitSet.bit_length]InstTracking, + free_registers: RegisterManager.RegisterBitSet, + inst_tracking_len: u32, + scope_generation: u32, }; -const BigTomb = struct { - function: *Self, - inst: Air.Inst.Index, - lbt: Liveness.BigTomb, +fn initRetroactiveState(self: *Self) State { + var state: State = undefined; + state.inst_tracking_len = @intCast(self.inst_tracking.count()); + state.scope_generation = self.scope_generation; + return state; +} - fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void { - const dies = bt.lbt.feed(); - const op_index = op_ref.toIndex() orelse return; - if (!dies) return; - bt.function.processDeath(op_index); +fn saveRetroactiveState(self: *Self, state: *State) !void { + const free_registers = self.register_manager.free_registers; + var it = free_registers.iterator(.{ .kind = .unset }); + while (it.next()) |index| { + const tracked_inst = self.register_manager.registers[index]; + state.registers[index] = tracked_inst; + state.reg_tracking[index] = self.inst_tracking.get(tracked_inst).?; + } + state.free_registers = free_registers; +} + +fn saveState(self: *Self) !State { + var state = self.initRetroactiveState(); + try self.saveRetroactiveState(&state); + return state; +} + +fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, comptime opts: struct { + emit_instructions: bool, + update_tracking: bool, + resurrect: bool, + close_scope: bool, +}) !void { + if (opts.close_scope) { + for ( + self.inst_tracking.keys()[state.inst_tracking_len..], + self.inst_tracking.values()[state.inst_tracking_len..], + ) |inst, *tracking| try tracking.die(self, inst); + self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len); } - fn finishAir(bt: *BigTomb, result: MCValue) void { - const is_used = !bt.function.liveness.isUnused(bt.inst); - if (is_used) { - log.debug("%{d} => {}", .{ bt.inst, result }); - const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; - branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); + if (opts.resurrect) for ( + self.inst_tracking.keys()[0..state.inst_tracking_len], + self.inst_tracking.values()[0..state.inst_tracking_len], + ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation); + for (deaths) |death| try self.processDeath(death); + + const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).Array.len]RegisterLock; + var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = + if (opts.update_tracking) + {} else std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); + + var reg_locks = if (opts.update_tracking) {} else try std.ArrayList(RegisterLock).initCapacity( + stack.get(), + @typeInfo(ExpectedContents).Array.len, + ); + defer if (!opts.update_tracking) { + for (reg_locks.items) |lock| self.register_manager.unlockReg(lock); + reg_locks.deinit(); + }; + + for (0..state.registers.len) |index| { + const current_maybe_inst = if (self.register_manager.free_registers.isSet(index)) + null + else + self.register_manager.registers[index]; + const target_maybe_inst = if (state.free_registers.isSet(index)) + null + else + state.registers[index]; + if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst| + assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len); + if (opts.emit_instructions) { + if (current_maybe_inst) |current_inst| { + try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst); + } + if (target_maybe_inst) |target_inst| { + const target_tracking = self.inst_tracking.getPtr(target_inst).?; + try target_tracking.materialize(self, target_inst, state.reg_tracking[index]); + } } - bt.function.finishAirBookkeeping(); + if (opts.update_tracking) { + if (current_maybe_inst) |current_inst| { + try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst); + } + { + const reg = RegisterManager.regAtTrackedIndex(@intCast(index)); + self.register_manager.freeReg(reg); + self.register_manager.getRegAssumeFree(reg, target_maybe_inst); + } + if (target_maybe_inst) |target_inst| { + self.inst_tracking.getPtr(target_inst).?.trackMaterialize( + target_inst, + state.reg_tracking[index], + ); + } + } else if (target_maybe_inst) |_| + try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(@intCast(index))); } -}; + + if (opts.update_tracking and std.debug.runtime_safety) { + assert(self.register_manager.free_registers.eql(state.free_registers)); + var used_reg_it = state.free_registers.iterator(.{ .kind = .unset }); + while (used_reg_it.next()) |index| + assert(self.register_manager.registers[index] == state.registers[index]); + } +} const Self = @This(); +const CallView = enum(u1) { + callee, + caller, +}; + pub fn generate( - lf: *link.File, + bin_file: *link.File, src_loc: Module.SrcLoc, func_index: InternPool.Index, air: Air, @@ -224,14 +705,17 @@ pub fn generate( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, ) CodeGenError!Result { - const gpa = lf.comp.gpa; - const zcu = lf.comp.module.?; + const comp = bin_file.comp; + const gpa = comp.gpa; + const zcu = comp.module.?; + const ip = &zcu.intern_pool; const func = zcu.funcInfo(func_index); const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.typeOf(zcu); const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); const target = &namespace.file_scope.mod.resolved_target.result; + const mod = namespace.file_scope.mod; var branch_stack = std.ArrayList(Branch).init(gpa); defer { @@ -244,9 +728,10 @@ pub fn generate( var function = Self{ .gpa = gpa, .air = air, + .mod = mod, .liveness = liveness, .target = target, - .bin_file = lf, + .bin_file = bin_file, .func_index = func_index, .code = code, .debug_output = debug_output, @@ -257,27 +742,69 @@ pub fn generate( .arg_index = 0, .branch_stack = &branch_stack, .src_loc = src_loc, - .stack_align = undefined, .end_di_line = func.rbrace_line, .end_di_column = func.rbrace_column, + .scope_generation = 0, }; - defer function.stack.deinit(gpa); - defer function.blocks.deinit(gpa); - defer function.exitlude_jump_relocs.deinit(gpa); + defer { + function.frame_allocs.deinit(gpa); + function.free_frame_indices.deinit(gpa); + function.frame_locs.deinit(gpa); + var block_it = function.blocks.valueIterator(); + while (block_it.next()) |block| block.deinit(gpa); + function.blocks.deinit(gpa); + function.inst_tracking.deinit(gpa); + function.const_tracking.deinit(gpa); + function.exitlude_jump_relocs.deinit(gpa); + function.mir_instructions.deinit(gpa); + function.mir_extra.deinit(gpa); + } - var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { + try function.frame_allocs.resize(gpa, FrameIndex.named_count); + function.frame_allocs.set( + @intFromEnum(FrameIndex.stack_frame), + FrameAlloc.init(.{ + .size = 0, + .alignment = func.analysis(ip).stack_alignment.max(.@"1"), + }), + ); + function.frame_allocs.set( + @intFromEnum(FrameIndex.call_frame), + FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), + ); + + const fn_info = zcu.typeToFunc(fn_type).?; + var call_info = function.resolveCallingConventionValues(fn_info) catch |err| switch (err) { error.CodegenFail => return Result{ .fail = function.err_msg.? }, error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, }; + defer call_info.deinit(&function); function.args = call_info.args; function.ret_mcv = call_info.return_value; - function.stack_align = call_info.stack_align; - function.max_end_stack = call_info.stack_byte_count; + function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ + .size = Type.usize.abiSize(zcu), + .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align), + })); + function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ + .size = Type.usize.abiSize(zcu), + .alignment = Alignment.min( + call_info.stack_align, + Alignment.fromNonzeroByteUnits(function.target.stackAlignment()), + ), + })); + function.frame_allocs.set(@intFromEnum(FrameIndex.args_frame), FrameAlloc.init(.{ + .size = call_info.stack_byte_count, + .alignment = call_info.stack_align, + })); + function.frame_allocs.set(@intFromEnum(FrameIndex.spill_frame), FrameAlloc.init(.{ + .size = 0, + .alignment = Type.usize.abiAlignment(zcu), + })); function.gen() catch |err| switch (err) { error.CodegenFail => return Result{ .fail = function.err_msg.? }, @@ -290,15 +817,22 @@ pub fn generate( var mir = Mir{ .instructions = function.mir_instructions.toOwnedSlice(), .extra = try function.mir_extra.toOwnedSlice(gpa), + .frame_locs = function.frame_locs.toOwnedSlice(), }; defer mir.deinit(gpa); var emit = Emit{ - .mir = mir, - .bin_file = lf, + .lower = .{ + .bin_file = bin_file, + .allocator = gpa, + .mir = mir, + .cc = fn_info.cc, + .src_loc = src_loc, + .output_mode = comp.config.output_mode, + .link_mode = comp.config.link_mode, + .pic = mod.pic, + }, .debug_output = debug_output, - .target = target, - .src_loc = src_loc, .code = code, .prev_di_pc = 0, .prev_di_line = func.lbrace_line, @@ -307,7 +841,20 @@ pub fn generate( defer emit.deinit(); emit.emitMir() catch |err| switch (err) { - error.EmitFail => return Result{ .fail = emit.err_msg.? }, + error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? }, + error.InvalidInstruction => |e| { + const msg = switch (e) { + error.InvalidInstruction => "CodeGen failed to find a viable instruction.", + }; + return Result{ + .fail = try ErrorMsg.create( + gpa, + src_loc, + "{s} This is a bug in the Zig compiler.", + .{msg}, + ), + }; + }, else => |e| return e, }; @@ -328,6 +875,30 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { return result_index; } +fn addNop(self: *Self) error{OutOfMemory}!Mir.Inst.Index { + return self.addInst(.{ + .tag = .nop, + .ops = .none, + .data = undefined, + }); +} + +fn addPseudoNone(self: *Self, ops: Mir.Inst.Ops) !void { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = ops, + .data = undefined, + }); +} + +fn addPseudo(self: *Self, ops: Mir.Inst.Ops) !Mir.Inst.Index { + return self.addInst(.{ + .tag = .pseudo, + .ops = ops, + .data = undefined, + }); +} + pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 { const fields = std.meta.fields(@TypeOf(extra)); try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len); @@ -349,122 +920,131 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { fn gen(self: *Self) !void { const mod = self.bin_file.comp.module.?; - const cc = self.fn_type.fnCallingConvention(mod); - if (cc != .Naked) { - // TODO Finish function prologue and epilogue for riscv64. + const fn_info = mod.typeToFunc(self.fn_type).?; - // TODO Backpatch stack offset - // addi sp, sp, -16 - _ = try self.addInst(.{ - .tag = .addi, - .data = .{ .i_type = .{ - .rd = .sp, - .rs1 = .sp, - .imm12 = -16, - } }, - }); + if (fn_info.cc != .Naked) { + try self.addPseudoNone(.pseudo_dbg_prologue_end); - // sd ra, 8(sp) - _ = try self.addInst(.{ - .tag = .sd, - .data = .{ .i_type = .{ - .rd = .ra, - .rs1 = .sp, - .imm12 = 8, - } }, - }); - - // sd s0, 0(sp) - _ = try self.addInst(.{ - .tag = .sd, - .data = .{ .i_type = .{ - .rd = .s0, - .rs1 = .sp, - .imm12 = 0, - } }, - }); - - _ = try self.addInst(.{ - .tag = .dbg_prologue_end, - .data = .{ .nop = {} }, - }); + const backpatch_stack_alloc = try self.addPseudo(.pseudo_dead); + const backpatch_ra_spill = try self.addPseudo(.pseudo_dead); + const backpatch_fp_spill = try self.addPseudo(.pseudo_dead); + const backpatch_fp_add = try self.addPseudo(.pseudo_dead); + const backpatch_spill_callee_preserved_regs = try self.addPseudo(.pseudo_dead); try self.genBody(self.air.getMainBody()); - _ = try self.addInst(.{ - .tag = .dbg_epilogue_begin, - .data = .{ .nop = {} }, - }); - - // exitlude jumps - if (self.exitlude_jump_relocs.items.len > 0 and - self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2) - { - // If the last Mir instruction (apart from the - // dbg_epilogue_begin) is the last exitlude jump - // relocation (which would just jump one instruction - // further), it can be safely removed - self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop()); - } - for (self.exitlude_jump_relocs.items) |jmp_reloc| { - _ = jmp_reloc; - return self.fail("TODO add branches in RISCV64", .{}); + self.mir_instructions.items(.data)[jmp_reloc].inst = + @intCast(self.mir_instructions.len); } - // ld ra, 8(sp) - _ = try self.addInst(.{ - .tag = .ld, - .data = .{ .i_type = .{ - .rd = .ra, - .rs1 = .sp, - .imm12 = 8, - } }, - }); + try self.addPseudoNone(.pseudo_dbg_epilogue_begin); - // ld s0, 0(sp) - _ = try self.addInst(.{ - .tag = .ld, - .data = .{ .i_type = .{ - .rd = .s0, - .rs1 = .sp, - .imm12 = 0, - } }, - }); + const backpatch_restore_callee_preserved_regs = try self.addPseudo(.pseudo_dead); + const backpatch_ra_restore = try self.addPseudo(.pseudo_dead); + const backpatch_fp_restore = try self.addPseudo(.pseudo_dead); + const backpatch_stack_alloc_restore = try self.addPseudo(.pseudo_dead); + try self.addPseudoNone(.pseudo_ret); - // addi sp, sp, 16 - _ = try self.addInst(.{ + const frame_layout = try self.computeFrameLayout(); + const need_save_reg = frame_layout.save_reg_list.count() > 0; + + self.mir_instructions.set(backpatch_stack_alloc, .{ .tag = .addi, + .ops = .rri, .data = .{ .i_type = .{ .rd = .sp, .rs1 = .sp, - .imm12 = 16, + .imm12 = Immediate.s(-@as(i32, @intCast(frame_layout.stack_adjust))), + } }, + }); + self.mir_instructions.set(backpatch_ra_spill, .{ + .tag = .pseudo, + .ops = .pseudo_store_rm, + .data = .{ .rm = .{ + .r = .ra, + .m = .{ + .base = .{ .frame = .ret_addr }, + .mod = .{ .rm = .{ .size = .dword } }, + }, + } }, + }); + self.mir_instructions.set(backpatch_ra_restore, .{ + .tag = .pseudo, + .ops = .pseudo_load_rm, + .data = .{ .rm = .{ + .r = .ra, + .m = .{ + .base = .{ .frame = .ret_addr }, + .mod = .{ .rm = .{ .size = .dword } }, + }, + } }, + }); + self.mir_instructions.set(backpatch_fp_spill, .{ + .tag = .pseudo, + .ops = .pseudo_store_rm, + .data = .{ .rm = .{ + .r = .s0, + .m = .{ + .base = .{ .frame = .base_ptr }, + .mod = .{ .rm = .{ .size = .dword } }, + }, + } }, + }); + self.mir_instructions.set(backpatch_fp_restore, .{ + .tag = .pseudo, + .ops = .pseudo_load_rm, + .data = .{ .rm = .{ + .r = .s0, + .m = .{ + .base = .{ .frame = .base_ptr }, + .mod = .{ .rm = .{ .size = .dword } }, + }, + } }, + }); + self.mir_instructions.set(backpatch_fp_add, .{ + .tag = .addi, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = .s0, + .rs1 = .sp, + .imm12 = Immediate.s(@intCast(frame_layout.stack_adjust)), + } }, + }); + self.mir_instructions.set(backpatch_stack_alloc_restore, .{ + .tag = .addi, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = .sp, + .rs1 = .sp, + .imm12 = Immediate.s(@intCast(frame_layout.stack_adjust)), } }, }); - // ret - _ = try self.addInst(.{ - .tag = .ret, - .data = .{ .nop = {} }, - }); + if (need_save_reg) { + self.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{ + .tag = .pseudo, + .ops = .pseudo_spill_regs, + .data = .{ .reg_list = frame_layout.save_reg_list }, + }); + + self.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{ + .tag = .pseudo, + .ops = .pseudo_restore_regs, + .data = .{ .reg_list = frame_layout.save_reg_list }, + }); + } } else { - _ = try self.addInst(.{ - .tag = .dbg_prologue_end, - .data = .{ .nop = {} }, - }); - + try self.addPseudoNone(.pseudo_dbg_prologue_end); try self.genBody(self.air.getMainBody()); - - _ = try self.addInst(.{ - .tag = .dbg_epilogue_begin, - .data = .{ .nop = {} }, - }); + try self.addPseudoNone(.pseudo_dbg_epilogue_begin); } // Drop them off at the rbrace. _ = try self.addInst(.{ - .tag = .dbg_line, - .data = .{ .dbg_line_column = .{ + .tag = .pseudo, + .ops = .pseudo_dbg_line_column, + .data = .{ .pseudo_dbg_line_column = .{ .line = self.end_di_line, .column = self.end_di_column, } }, @@ -472,18 +1052,15 @@ fn gen(self: *Self) !void { } fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { - const mod = self.bin_file.comp.module.?; - const ip = &mod.intern_pool; + const zcu = self.bin_file.comp.module.?; + const ip = &zcu.intern_pool; const air_tags = self.air.instructions.items(.tag); for (body) |inst| { - // TODO: remove now-redundant isUnused calls from AIR handler functions - if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) - continue; + if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; const old_air_bookkeeping = self.air_bookkeeping; - try self.ensureProcessDeathCapacity(Liveness.bpi); - + try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); switch (air_tags[@intFromEnum(inst)]) { // zig fmt: off .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), @@ -508,8 +1085,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .mod => try self.airMod(inst), .shl, .shl_exact => try self.airShl(inst), .shl_sat => try self.airShlSat(inst), - .min => try self.airMin(inst), - .max => try self.airMax(inst), + .min => try self.airMinMax(inst, .min), + .max => try self.airMinMax(inst, .max), .slice => try self.airSlice(inst), .sqrt, @@ -535,12 +1112,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), - .cmp_lt => try self.airCmp(inst, .lt), - .cmp_lte => try self.airCmp(inst, .lte), - .cmp_eq => try self.airCmp(inst, .eq), - .cmp_gte => try self.airCmp(inst, .gte), - .cmp_gt => try self.airCmp(inst, .gt), - .cmp_neq => try self.airCmp(inst, .neq), + .cmp_lt => try self.airCmp(inst), + .cmp_lte => try self.airCmp(inst), + .cmp_eq => try self.airCmp(inst), + .cmp_gte => try self.airCmp(inst), + .cmp_gt => try self.airCmp(inst), + .cmp_neq => try self.airCmp(inst), .cmp_vector => try self.airCmpVector(inst), .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), @@ -565,11 +1142,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .frame_addr => try self.airFrameAddress(inst), .fence => try self.airFence(), .cond_br => try self.airCondBr(inst), + .dbg_stmt => try self.airDbgStmt(inst), .fptrunc => try self.airFptrunc(inst), .fpext => try self.airFpext(inst), .intcast => try self.airIntCast(inst), .trunc => try self.airTrunc(inst), - .int_from_bool => try self.airIntFromBool(inst), + .int_from_bool => try self.airIntFromBool(inst), .is_non_null => try self.airIsNonNull(inst), .is_non_null_ptr => try self.airIsNonNullPtr(inst), .is_null => try self.airIsNull(inst), @@ -581,17 +1159,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .load => try self.airLoad(inst), .loop => try self.airLoop(inst), .not => try self.airNot(inst), - .int_from_ptr => try self.airIntFromPtr(inst), - .ret => try self.airRet(inst), - .ret_safe => try self.airRet(inst), // TODO + .int_from_ptr => try self.airIntFromPtr(inst), + .ret => try self.airRet(inst, false), + .ret_safe => try self.airRet(inst, true), .ret_load => try self.airRetLoad(inst), .store => try self.airStore(inst, false), .store_safe => try self.airStore(inst, true), .struct_field_ptr=> try self.airStructFieldPtr(inst), .struct_field_val=> try self.airStructFieldVal(inst), .array_to_slice => try self.airArrayToSlice(inst), - .float_from_int => try self.airFloatFromInt(inst), - .int_from_float => try self.airIntFromFloat(inst), + .float_from_int => try self.airFloatFromInt(inst), + .int_from_float => try self.airIntFromFloat(inst), .cmpxchg_strong => try self.airCmpxchg(inst), .cmpxchg_weak => try self.airCmpxchg(inst), .atomic_rmw => try self.airAtomicRmw(inst), @@ -617,17 +1195,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .union_init => try self.airUnionInit(inst), .prefetch => try self.airPrefetch(inst), .mul_add => try self.airMulAdd(inst), - .addrspace_cast => @panic("TODO"), + .addrspace_cast => return self.fail("TODO: addrspace_cast", .{}), - .@"try" => @panic("TODO"), - .try_ptr => @panic("TODO"), + .@"try" => try self.airTry(inst), + .try_ptr => return self.fail("TODO: try_ptr", .{}), - .dbg_stmt => try self.airDbgStmt(inst), - .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, => try self.airDbgVar(inst), + .dbg_inline_block => try self.airDbgInlineBlock(inst), + .call => try self.airCall(inst, .auto), .call_always_tail => try self.airCall(inst, .always_tail), .call_never_tail => try self.airCall(inst, .never_tail), @@ -715,28 +1293,60 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .work_group_id => unreachable, // zig fmt: on } + + assert(!self.register_manager.lockedRegsExist()); + if (std.debug.runtime_safety) { if (self.air_bookkeeping < old_air_bookkeeping + 1) { 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)] }); } + + { // check consistency of tracked registers + var it = self.register_manager.free_registers.iterator(.{ .kind = .unset }); + while (it.next()) |index| { + const tracked_inst = self.register_manager.registers[index]; + const tracking = self.getResolvedInstValue(tracked_inst); + for (tracking.getRegs()) |reg| { + if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; + } else return self.fail( + \\%{} takes up these regs: {any}, however those regs don't use it + , .{ index, tracking.getRegs() }); + } + } } } } -/// Asserts there is already capacity to insert into top branch inst_table. -fn processDeath(self: *Self, inst: Air.Inst.Index) void { - // When editing this function, note that the logic must synchronize with `reuseOperand`. - const prev_value = self.getResolvedInstValue(inst); - const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; - branch.inst_table.putAssumeCapacity(inst, .dead); - switch (prev_value) { - .register => |reg| { - self.register_manager.freeReg(reg); - }, +fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) !void { + for (value.getRegs()) |reg| try self.register_manager.getReg(reg, inst); +} + +fn getValueIfFree(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { + for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg)) + self.register_manager.getRegAssumeFree(reg, inst); +} + +fn freeValue(self: *Self, value: MCValue) !void { + switch (value) { + .register => |reg| self.register_manager.freeReg(reg), + .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg), + .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg), else => {}, // TODO process stack allocation death } } +fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void { + if (bt.feed()) if (operand.toIndex()) |inst| { + log.debug("feed inst: %{}", .{inst}); + try self.processDeath(inst); + }; +} + +/// Asserts there is already capacity to insert into top branch inst_table. +fn processDeath(self: *Self, inst: Air.Inst.Index) !void { + try self.inst_tracking.getPtr(inst).?.die(self, inst); +} + /// Called when there are no operands, and the instruction is always unreferenced. fn finishAirBookkeeping(self: *Self) void { if (std.debug.runtime_safety) { @@ -744,36 +1354,143 @@ fn finishAirBookkeeping(self: *Self) void { } } -fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void { +fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void { + if (self.liveness.isUnused(inst)) switch (result) { + .none, .dead, .unreach => {}, + else => unreachable, // Why didn't the result die? + } else { + tracking_log.debug("%{d} => {} (birth)", .{ inst, result }); + self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(result)); + // In some cases, an operand may be reused as the result. + // If that operand died and was a register, it was freed by + // processDeath, so we have to "re-allocate" the register. + self.getValueIfFree(result, inst); + } + self.finishAirBookkeeping(); +} + +fn finishAir( + self: *Self, + inst: Air.Inst.Index, + result: MCValue, + operands: [Liveness.bpi - 1]Air.Inst.Ref, +) !void { var tomb_bits = self.liveness.getTombBits(inst); for (operands) |op| { const dies = @as(u1, @truncate(tomb_bits)) != 0; tomb_bits >>= 1; if (!dies) continue; - const op_index = op.toIndex() orelse continue; - self.processDeath(op_index); + try self.processDeath(op.toIndexAllowNone() orelse continue); } - const is_used = @as(u1, @truncate(tomb_bits)) == 0; - if (is_used) { - log.debug("%{d} => {}", .{ inst, result }); - const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; - branch.inst_table.putAssumeCapacityNoClobber(inst, result); + self.finishAirResult(inst, result); +} - switch (result) { - .register => |reg| { - // In some cases (such as bitcast), an operand - // may be the same MCValue as the result. If - // that operand died and was a register, it - // was freed by processDeath. We have to - // "re-allocate" the register. - if (self.register_manager.isRegFree(reg)) { - self.register_manager.getRegAssumeFree(reg, inst); - } - }, - else => {}, +const FrameLayout = struct { + stack_adjust: u32, + save_reg_list: Mir.RegisterList, +}; + +fn setFrameLoc( + self: *Self, + frame_index: FrameIndex, + base: Register, + offset: *i32, + comptime aligned: bool, +) void { + const frame_i = @intFromEnum(frame_index); + if (aligned) { + const alignment: InternPool.Alignment = self.frame_allocs.items(.abi_align)[frame_i]; + offset.* = if (math.sign(offset.*) < 0) + -1 * @as(i32, @intCast(alignment.backward(@intCast(@abs(offset.*))))) + else + @intCast(alignment.forward(@intCast(@abs(offset.*)))); + } + self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* }); + offset.* += self.frame_allocs.items(.abi_size)[frame_i]; +} + +fn computeFrameLayout(self: *Self) !FrameLayout { + const frame_allocs_len = self.frame_allocs.len; + try self.frame_locs.resize(self.gpa, frame_allocs_len); + const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); + defer self.gpa.free(stack_frame_order); + + const frame_size = self.frame_allocs.items(.abi_size); + const frame_align = self.frame_allocs.items(.abi_align); + + for (stack_frame_order, FrameIndex.named_count..) |*frame_order, frame_index| + frame_order.* = @enumFromInt(frame_index); + + { + const SortContext = struct { + frame_align: @TypeOf(frame_align), + pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool { + return context.frame_align[@intFromEnum(lhs)].compare(.gt, context.frame_align[@intFromEnum(rhs)]); + } + }; + const sort_context = SortContext{ .frame_align = frame_align }; + mem.sort(FrameIndex, stack_frame_order, sort_context, SortContext.lessThan); + } + + var save_reg_list = Mir.RegisterList{}; + for (callee_preserved_regs) |reg| { + if (self.register_manager.isRegAllocated(reg)) { + save_reg_list.push(&callee_preserved_regs, reg); } } - self.finishAirBookkeeping(); + + const total_alloc_size: i32 = blk: { + var i: i32 = 0; + for (stack_frame_order) |frame_index| { + i += frame_size[@intFromEnum(frame_index)]; + } + break :blk i; + }; + const saved_reg_size = save_reg_list.size(); + + frame_size[@intFromEnum(FrameIndex.spill_frame)] = @intCast(saved_reg_size); + + // The total frame size is calculated by the amount of s registers you need to save * 8, as each + // register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s0 + // register. Finally we align the frame size to the align of the base pointer. + const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)]; + const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)]; + const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)]; + + // TODO: this 64 should be a 16, but we were clobbering the top and bottom of the frame. + // maybe everything can go from the bottom? + const acc_frame_size: i32 = std.mem.alignForward( + i32, + total_alloc_size + 64 + args_frame_size + spill_frame_size + call_frame_size, + @intCast(frame_align[@intFromEnum(FrameIndex.base_ptr)].toByteUnits().?), + ); + log.debug("frame size: {}", .{acc_frame_size}); + + // store the ra at total_size - 8, so it's the very first thing in the stack + // relative to the fp + self.frame_locs.set( + @intFromEnum(FrameIndex.ret_addr), + .{ .base = .sp, .disp = acc_frame_size - 8 }, + ); + self.frame_locs.set( + @intFromEnum(FrameIndex.base_ptr), + .{ .base = .sp, .disp = acc_frame_size - 16 }, + ); + + // now we grow the stack frame from the bottom of total frame in order to + // not need to know the size of the first allocation. Stack offsets point at the "bottom" + // of variables. + var s0_offset: i32 = -acc_frame_size; + self.setFrameLoc(.stack_frame, .s0, &s0_offset, true); + for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .s0, &s0_offset, true); + self.setFrameLoc(.args_frame, .s0, &s0_offset, true); + self.setFrameLoc(.call_frame, .s0, &s0_offset, true); + self.setFrameLoc(.spill_frame, .s0, &s0_offset, true); + + return .{ + .stack_adjust = @intCast(acc_frame_size), + .save_reg_list = save_reg_list, + }; } fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { @@ -781,40 +1498,94 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { try table.ensureUnusedCapacity(self.gpa, additional_count); } -fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { - self.stack_align = self.stack_align.max(abi_align); - // TODO find a free slot instead of always appending - const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset)); - self.next_stack_offset = offset + abi_size; - if (self.next_stack_offset > self.max_end_stack) - self.max_end_stack = self.next_stack_offset; - try self.stack.putNoClobber(self.gpa, offset, .{ - .inst = inst, - .size = abi_size, - }); - return offset; +fn memSize(self: *Self, ty: Type) Memory.Size { + const mod = self.bin_file.comp.module.?; + return switch (ty.zigTypeTag(mod)) { + .Float => Memory.Size.fromBitSize(ty.floatBits(self.target.*)), + else => Memory.Size.fromByteSize(ty.abiSize(mod)), + }; +} + +fn splitType(self: *Self, ty: Type) ![2]Type { + const zcu = self.bin_file.comp.module.?; + const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none); + var parts: [2]Type = undefined; + if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| { + part.* = switch (class) { + .integer => switch (part_i) { + 0 => Type.u64, + 1 => part: { + const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?; + const elem_ty = try zcu.intType(.unsigned, @intCast(elem_size * 8)); + break :part switch (@divExact(ty.abiSize(zcu) - 8, elem_size)) { + 1 => elem_ty, + else => |len| try zcu.arrayType(.{ .len = len, .child = elem_ty.toIntern() }), + }; + }, + else => unreachable, + }, + else => return self.fail("TODO: splitType class {}", .{class}), + }; + } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts; + return self.fail("TODO implement splitType for {}", .{ty.fmt(zcu)}); +} + +fn symbolIndex(self: *Self) !u32 { + const zcu = self.bin_file.comp.module.?; + const decl_index = zcu.funcOwnerDeclIndex(self.func_index); + return switch (self.bin_file.tag) { + .elf => blk: { + const elf_file = self.bin_file.cast(link.File.Elf).?; + const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); + break :blk atom_index; + }, + else => return self.fail("TODO genSetReg load_symbol for {s}", .{@tagName(self.bin_file.tag)}), + }; +} + +fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { + const frame_allocs_slice = self.frame_allocs.slice(); + const frame_size = frame_allocs_slice.items(.abi_size); + const frame_align = frame_allocs_slice.items(.abi_align); + + const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)]; + stack_frame_align.* = stack_frame_align.max(alloc.abi_align); + + for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { + const abi_size = frame_size[@intFromEnum(frame_index)]; + if (abi_size != alloc.abi_size) continue; + const abi_align = &frame_align[@intFromEnum(frame_index)]; + abi_align.* = abi_align.max(alloc.abi_align); + + _ = self.free_frame_indices.swapRemoveAt(free_i); + return frame_index; + } + const frame_index: FrameIndex = @enumFromInt(self.frame_allocs.len); + try self.frame_allocs.append(self.gpa, alloc); + log.debug("allocated frame {}", .{frame_index}); + return frame_index; } /// Use a pointer instruction as the basis for allocating stack memory. -fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { - const mod = self.bin_file.comp.module.?; - const elem_ty = self.typeOfIndex(inst).childType(mod); - const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); - }; - // TODO swap this for inst.ty.ptrAlign - const abi_align = elem_ty.abiAlignment(mod); - return self.allocMem(inst, abi_size, abi_align); +fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { + const zcu = self.bin_file.comp.module.?; + const ptr_ty = self.typeOfIndex(inst); + const val_ty = ptr_ty.childType(zcu); + return self.allocFrameIndex(FrameAlloc.init(.{ + .size = math.cast(u32, val_ty.abiSize(zcu)) orelse { + return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(zcu)}); + }, + .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"), + })); } fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { - const mod = self.bin_file.comp.module.?; + const zcu = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst); - const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); + + const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { + return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)}); }; - const abi_align = elem_ty.abiAlignment(mod); - self.stack_align = self.stack_align.max(abi_align); if (reg_ok) { // Make sure the type can fit in a register before we try to allocate one. @@ -822,29 +1593,67 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const ptr_bytes: u64 = @divExact(ptr_bits, 8); if (abi_size <= ptr_bytes) { if (self.register_manager.tryAllocReg(inst, gp)) |reg| { - return MCValue{ .register = reg }; + return .{ .register = reg }; } } } - const stack_offset = try self.allocMem(inst, abi_size, abi_align); - return MCValue{ .stack_offset = stack_offset }; + + const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(elem_ty, zcu)); + return .{ .load_frame = .{ .index = frame_index } }; +} + +/// Allocates a register from the general purpose set and returns the Register and the Lock. +/// +/// Up to the user to unlock the register later. +fn allocReg(self: *Self) !struct { Register, RegisterLock } { + const reg = try self.register_manager.allocReg(null, gp); + const lock = self.register_manager.lockRegAssumeUnused(reg); + return .{ reg, lock }; +} + +fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { + const reg: Register = blk: { + switch (index) { + .immediate => |imm| { + // Optimisation: if index MCValue is an immediate, we can multiply in `comptime` + // and set the register directly to the scaled offset as an immediate. + const reg = try self.register_manager.allocReg(null, gp); + try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size }); + break :blk reg; + }, + else => { + const reg = try self.copyToTmpRegister(index_ty, index); + const lock = self.register_manager.lockRegAssumeUnused(reg); + defer self.register_manager.unlockReg(lock); + + const result = try self.binOp( + .mul, + .{ .register = reg }, + index_ty, + .{ .immediate = elem_size }, + index_ty, + ); + break :blk result.register; + }, + } + }; + return reg; } pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { - const stack_mcv = try self.allocRegOrMem(inst, false); - log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); - const reg_mcv = self.getResolvedInstValue(inst); - assert(reg == reg_mcv.register); - const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; - try branch.inst_table.put(self.gpa, inst, stack_mcv); - try self.genSetStack(self.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); + const tracking = self.inst_tracking.getPtr(inst) orelse return; + for (tracking.getRegs()) |tracked_reg| { + if (tracked_reg.id() == reg.id()) break; + } else unreachable; // spilled reg not tracked with spilled instruciton + try tracking.spill(self, inst); + try tracking.trackSpill(self, inst); } /// Copies a value to a register without tracking the register. The register is not considered /// allocated. A second call to `copyToTmpRegister` may return the same register. /// This can have a side effect of spilling instructions to the stack to free up a register. fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { - const reg = try self.register_manager.allocReg(null, gp); + const reg = try self.register_manager.allocReg(null, tp); try self.genSetReg(ty, reg, mcv); return reg; } @@ -859,51 +1668,84 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa } fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { - const stack_offset = try self.allocMemPtr(inst); - return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); + const result = MCValue{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } }; + return self.finishAir(inst, result, .{ .none, .none, .none }); } fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { - const stack_offset = try self.allocMemPtr(inst); - return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); + const result: MCValue = switch (self.ret_mcv.long) { + .none => .{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } }, + .load_frame => .{ .register_offset = .{ + .reg = (try self.copyToNewRegister( + inst, + self.ret_mcv.long, + )).register, + .off = self.ret_mcv.short.indirect.off, + } }, + else => |t| return self.fail("TODO: airRetPtr {s}", .{@tagName(t)}), + }; + return self.finishAir(inst, result, .{ .none, .none, .none }); } fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airFpext(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - if (self.liveness.isUnused(inst)) - return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + const src_ty = self.typeOf(ty_op.operand); + const dst_ty = self.typeOfIndex(inst); - const mod = self.bin_file.comp.module.?; - const operand_ty = self.typeOf(ty_op.operand); - const operand = try self.resolveInst(ty_op.operand); - const info_a = operand_ty.intInfo(mod); - const info_b = self.typeOfIndex(inst).intInfo(mod); - if (info_a.signedness != info_b.signedness) - return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); + const result: MCValue = result: { + const src_int_info = src_ty.intInfo(zcu); + const dst_int_info = dst_ty.intInfo(zcu); - if (info_a.bits == info_b.bits) - return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); + const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; - return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); + const src_mcv = try self.resolveInst(ty_op.operand); + + const src_storage_bits: u16 = switch (src_mcv) { + .register => 64, + .load_frame => src_int_info.bits, + else => return self.fail("airIntCast from {s}", .{@tagName(src_mcv)}), + }; + + const dst_mcv = if (dst_int_info.bits <= src_storage_bits and + math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == + math.divCeil(u32, src_storage_bits, 64) catch unreachable and + self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(min_ty, dst_mcv, src_mcv); + break :dst dst_mcv; + }; + + if (dst_int_info.bits <= src_int_info.bits) + break :result dst_mcv; + + if (dst_int_info.bits > 64 or src_int_info.bits > 64) + break :result null; // TODO + + break :result dst_mcv; + } orelse return self.fail("TODO implement airIntCast from {} to {}", .{ + src_ty.fmt(zcu), dst_ty.fmt(zcu), + }); + + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; if (self.liveness.isUnused(inst)) - return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none }); const operand = try self.resolveInst(ty_op.operand); _ = operand; @@ -914,130 +1756,169 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else operand; + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else operand; return self.finishAir(inst, result, .{ un_op, .none, .none }); } fn airNot(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const zcu = self.bin_file.comp.module.?; + + const operand = try self.resolveInst(ty_op.operand); + const ty = self.typeOf(ty_op.operand); + + switch (ty.zigTypeTag(zcu)) { + .Bool => { + const operand_reg = blk: { + if (operand == .register) break :blk operand.register; + break :blk try self.copyToTmpRegister(ty, operand); + }; + + const dst_reg: Register = + if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) + operand.register + else + try self.register_manager.allocReg(inst, gp); + + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_not, + .data = .{ + .rr = .{ + .rs = operand_reg, + .rd = dst_reg, + }, + }, + }); + + break :result .{ .register = dst_reg }; + }, + .Int => return self.fail("TODO: airNot ints", .{}), + else => unreachable, + } + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } -fn airMin(self: *Self, inst: Air.Inst.Index) !void { +fn airMinMax( + self: *Self, + inst: Air.Inst.Index, + comptime tag: enum { + max, + min, + }, +) !void { + const zcu = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement min for {}", .{self.target.cpu.arch}); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} -fn airMax(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement max for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.typeOf(bin_op.lhs); + const rhs_ty = self.typeOf(bin_op.rhs); + + const int_info = lhs_ty.intInfo(zcu); + + if (int_info.bits > 64) return self.fail("TODO: > 64 bit @min", .{}); + + const lhs_reg, const lhs_lock = blk: { + if (lhs == .register) break :blk .{ lhs.register, null }; + + const lhs_reg, const lhs_lock = try self.allocReg(); + try self.genSetReg(lhs_ty, lhs_reg, lhs); + break :blk .{ lhs_reg, lhs_lock }; + }; + defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); + + const rhs_reg, const rhs_lock = blk: { + if (rhs == .register) break :blk .{ rhs.register, null }; + + const rhs_reg, const rhs_lock = try self.allocReg(); + try self.genSetReg(rhs_ty, rhs_reg, rhs); + break :blk .{ rhs_reg, rhs_lock }; + }; + defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); + + const mask_reg, const mask_lock = try self.allocReg(); + defer self.register_manager.unlockReg(mask_lock); + + const result_reg, const result_lock = try self.allocReg(); + defer self.register_manager.unlockReg(result_lock); + + _ = try self.addInst(.{ + .tag = if (int_info.signedness == .unsigned) .sltu else .slt, + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = mask_reg, + .rs1 = lhs_reg, + .rs2 = rhs_reg, + } }, + }); + + _ = try self.addInst(.{ + .tag = .sub, + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = mask_reg, + .rs1 = .zero, + .rs2 = mask_reg, + } }, + }); + + _ = try self.addInst(.{ + .tag = .xor, + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = result_reg, + .rs1 = lhs_reg, + .rs2 = rhs_reg, + } }, + }); + + _ = try self.addInst(.{ + .tag = .@"and", + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = mask_reg, + .rs1 = result_reg, + .rs2 = mask_reg, + } }, + }); + + _ = try self.addInst(.{ + .tag = .xor, + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = result_reg, + .rs1 = if (tag == .min) rhs_reg else lhs_reg, + .rs2 = mask_reg, + } }, + }); + + break :result .{ .register = result_reg }; + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airSlice(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement slice for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -/// Don't call this function directly. Use binOp instead. -/// -/// Calling this function signals an intention to generate a Mir -/// instruction of the form -/// -/// op dest, lhs, rhs -/// -/// Asserts that generating an instruction of that form is possible. -fn binOpRegister( - self: *Self, - tag: Air.Inst.Tag, - maybe_inst: ?Air.Inst.Index, - lhs: MCValue, - rhs: MCValue, - lhs_ty: Type, - rhs_ty: Type, -) !MCValue { - const lhs_is_register = lhs == .register; - const rhs_is_register = rhs == .register; +fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { + const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.typeOf(bin_op.lhs); + const rhs_ty = self.typeOf(bin_op.rhs); - const lhs_lock: ?RegisterLock = if (lhs_is_register) - self.register_manager.lockReg(lhs.register) - else - null; - defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); - - const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; - - const lhs_reg = if (lhs_is_register) lhs.register else blk: { - const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { - const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - break :inst bin_op.lhs.toIndex().?; - } else null; - - const reg = try self.register_manager.allocReg(track_inst, gp); - - if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); - - break :blk reg; + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty); }; - const new_lhs_lock = self.register_manager.lockReg(lhs_reg); - defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); - - const rhs_reg = if (rhs_is_register) rhs.register else blk: { - const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { - const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - break :inst bin_op.rhs.toIndex().?; - } else null; - - const reg = try self.register_manager.allocReg(track_inst, gp); - - if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); - - break :blk reg; - }; - const new_rhs_lock = self.register_manager.lockReg(rhs_reg); - defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); - - const dest_reg = if (maybe_inst) |inst| blk: { - const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - - if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { - break :blk lhs_reg; - } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { - break :blk rhs_reg; - } else { - break :blk try self.register_manager.allocReg(inst, gp); - } - } else try self.register_manager.allocReg(null, gp); - - if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); - if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); - - const mir_tag: Mir.Inst.Tag = switch (tag) { - .add => .add, - .sub => .sub, - else => unreachable, - }; - const mir_data: Mir.Inst.Data = switch (tag) { - .add, - .sub, - => .{ .r_type = .{ - .rd = dest_reg, - .rs1 = lhs_reg, - .rs2 = rhs_reg, - } }, - else => unreachable, - }; - - _ = try self.addInst(.{ - .tag = mir_tag, - .data = mir_data, - }); - - return MCValue{ .register = dest_reg }; + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } /// For all your binary operation needs, this function will generate @@ -1052,48 +1933,57 @@ fn binOpRegister( /// looks at the lhs and rhs and determines which kind of lowering /// would be best suitable and then delegates the lowering to other /// functions. +/// +/// `maybe_inst` **needs** to be a bin_op, make sure of that. fn binOp( self: *Self, tag: Air.Inst.Tag, - maybe_inst: ?Air.Inst.Index, lhs: MCValue, - rhs: MCValue, lhs_ty: Type, + rhs: MCValue, rhs_ty: Type, ) InnerError!MCValue { - const mod = self.bin_file.comp.module.?; + const zcu = self.bin_file.comp.module.?; + switch (tag) { // Arithmetic operations on integers and floats .add, .sub, + .mul, + .cmp_eq, + .cmp_neq, + .cmp_gt, + .cmp_gte, + .cmp_lt, + .cmp_lte, => { - switch (lhs_ty.zigTypeTag(mod)) { + switch (lhs_ty.zigTypeTag(zcu)) { .Float => return self.fail("TODO binary operations on floats", .{}), .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { - assert(lhs_ty.eql(rhs_ty, mod)); - const int_info = lhs_ty.intInfo(mod); + assert(lhs_ty.eql(rhs_ty, zcu)); + const int_info = lhs_ty.intInfo(zcu); if (int_info.bits <= 64) { - // TODO immediate operands - return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); + return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty); } else { return self.fail("TODO binary operations on int with bits > 64", .{}); } }, - else => unreachable, + else => |x| return self.fail("TOOD: binOp {s}", .{@tagName(x)}), } }, + .ptr_add, .ptr_sub, => { - switch (lhs_ty.zigTypeTag(mod)) { + switch (lhs_ty.zigTypeTag(zcu)) { .Pointer => { const ptr_ty = lhs_ty; - const elem_ty = switch (ptr_ty.ptrSize(mod)) { - .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type - else => ptr_ty.childType(mod), + const elem_ty = switch (ptr_ty.ptrSize(zcu)) { + .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type + else => ptr_ty.childType(zcu), }; - const elem_size = elem_ty.abiSize(mod); + const elem_size = elem_ty.abiSize(zcu); if (elem_size == 1) { const base_tag: Air.Inst.Tag = switch (tag) { @@ -1102,27 +1992,167 @@ fn binOp( else => unreachable, }; - return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); + return try self.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty); } else { - return self.fail("TODO ptr_add with elem_size > 1", .{}); + const offset = try self.binOp( + .mul, + rhs, + Type.usize, + .{ .immediate = elem_size }, + Type.usize, + ); + + const addr = try self.binOp( + tag, + lhs, + Type.manyptr_u8, + offset, + Type.usize, + ); + return addr; } }, else => unreachable, } }, - else => unreachable, + + // These instructions have unsymteric bit sizes on RHS and LHS. + .shr, + .shl, + => { + switch (lhs_ty.zigTypeTag(zcu)) { + .Float => return self.fail("TODO binary operations on floats", .{}), + .Vector => return self.fail("TODO binary operations on vectors", .{}), + .Int => { + const int_info = lhs_ty.intInfo(zcu); + if (int_info.bits <= 64) { + return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty); + } else { + return self.fail("TODO binary operations on int with bits > 64", .{}); + } + }, + else => unreachable, + } + }, + else => return self.fail("TODO binOp {}", .{tag}), } } +/// Don't call this function directly. Use binOp instead. +/// +/// Calling this function signals an intention to generate a Mir +/// instruction of the form +/// +/// op dest, lhs, rhs +/// +/// Asserts that generating an instruction of that form is possible. +fn binOpRegister( + self: *Self, + tag: Air.Inst.Tag, + lhs: MCValue, + lhs_ty: Type, + rhs: MCValue, + rhs_ty: Type, +) !MCValue { + const lhs_reg, const lhs_lock = blk: { + if (lhs == .register) break :blk .{ lhs.register, null }; -fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { - const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - const lhs_ty = self.typeOf(bin_op.lhs); - const rhs_ty = self.typeOf(bin_op.rhs); + const lhs_reg, const lhs_lock = try self.allocReg(); + try self.genSetReg(lhs_ty, lhs_reg, lhs); + break :blk .{ lhs_reg, lhs_lock }; + }; + defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); + const rhs_reg, const rhs_lock = blk: { + if (rhs == .register) break :blk .{ rhs.register, null }; + + const rhs_reg, const rhs_lock = try self.allocReg(); + try self.genSetReg(rhs_ty, rhs_reg, rhs); + break :blk .{ rhs_reg, rhs_lock }; + }; + defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); + + const dest_reg, const dest_lock = try self.allocReg(); + defer self.register_manager.unlockReg(dest_lock); + + const mir_tag: Mir.Inst.Tag = switch (tag) { + .add => .add, + .sub => .sub, + .mul => .mul, + + .shl => .sllw, + .shr => .srlw, + + .cmp_eq, + .cmp_neq, + .cmp_gt, + .cmp_gte, + .cmp_lt, + .cmp_lte, + => .pseudo, + + else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), + }; + + switch (mir_tag) { + .add, + .sub, + .mul, + .sllw, + .srlw, + => { + _ = try self.addInst(.{ + .tag = mir_tag, + .ops = .rrr, + .data = .{ + .r_type = .{ + .rd = dest_reg, + .rs1 = lhs_reg, + .rs2 = rhs_reg, + }, + }, + }); + }, + + .pseudo => { + const pseudo_op = switch (tag) { + .cmp_eq, + .cmp_neq, + .cmp_gt, + .cmp_gte, + .cmp_lt, + .cmp_lte, + => .pseudo_compare, + else => unreachable, + }; + + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = pseudo_op, + .data = .{ + .compare = .{ + .rd = dest_reg, + .rs1 = lhs_reg, + .rs2 = rhs_reg, + .op = switch (tag) { + .cmp_eq => .eq, + .cmp_neq => .neq, + .cmp_gt => .gt, + .cmp_gte => .gte, + .cmp_lt => .lt, + .cmp_lte => .lte, + else => unreachable, + }, + }, + }, + }); + }, + + else => unreachable, + } + + // generate the struct for OF checks + + return MCValue{ .register = dest_reg }; } fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { @@ -1133,55 +2163,150 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void const lhs_ty = self.typeOf(bin_op.lhs); const rhs_ty = self.typeOf(bin_op.rhs); - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty); + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + // RISCV arthemtic instructions already wrap, so this is simply a sub binOp with + // no overflow checks. + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.typeOf(bin_op.lhs); + const rhs_ty = self.typeOf(bin_op.rhs); + + break :result try self.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty); + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airMul(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mul for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { - _ = inst; - return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); + const zcu = self.bin_file.comp.module.?; + const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; + const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; + + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const lhs = try self.resolveInst(extra.lhs); + const rhs = try self.resolveInst(extra.rhs); + const lhs_ty = self.typeOf(extra.lhs); + const rhs_ty = self.typeOf(extra.rhs); + + const int_info = lhs_ty.intInfo(zcu); + + const tuple_ty = self.typeOfIndex(inst); + const result_mcv = try self.allocRegOrMem(inst, false); + const offset = result_mcv.load_frame; + + if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { + const add_result = try self.binOp(.add, lhs, lhs_ty, rhs, rhs_ty); + const add_result_reg = try self.copyToTmpRegister(lhs_ty, add_result); + const add_result_reg_lock = self.register_manager.lockRegAssumeUnused(add_result_reg); + defer self.register_manager.unlockReg(add_result_reg_lock); + + const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits); + + const shift_reg, const shift_lock = try self.allocReg(); + defer self.register_manager.unlockReg(shift_lock); + + _ = try self.addInst(.{ + .tag = .slli, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = shift_reg, + .rs1 = add_result_reg, + .imm12 = Immediate.s(shift_amount), + }, + }, + }); + + _ = try self.addInst(.{ + .tag = if (int_info.signedness == .unsigned) .srli else .srai, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = shift_reg, + .rs1 = shift_reg, + .imm12 = Immediate.s(shift_amount), + }, + }, + }); + + const add_result_frame: FrameAddr = .{ + .index = offset.index, + .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))), + }; + try self.genSetStack( + lhs_ty, + add_result_frame, + add_result, + ); + + const overflow_mcv = try self.binOp( + .cmp_neq, + .{ .register = shift_reg }, + lhs_ty, + .{ .register = add_result_reg }, + lhs_ty, + ); + + const overflow_frame: FrameAddr = .{ + .index = offset.index, + .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))), + }; + try self.genSetStack( + Type.u1, + overflow_frame, + overflow_mcv, + ); + + break :result result_mcv; + } else { + return self.fail("TODO: less than 8 bit or non-pow 2 addition", .{}); + } + }; + + return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); } fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { @@ -1190,8 +2315,104 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { - _ = inst; - return self.fail("TODO implement airMulWithOverflow for {}", .{self.target.cpu.arch}); + //const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; + const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; + const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; + const zcu = self.bin_file.comp.module.?; + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const lhs = try self.resolveInst(extra.lhs); + const rhs = try self.resolveInst(extra.rhs); + const lhs_ty = self.typeOf(extra.lhs); + const rhs_ty = self.typeOf(extra.rhs); + + switch (lhs_ty.zigTypeTag(zcu)) { + else => |x| return self.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}), + .Int => { + assert(lhs_ty.eql(rhs_ty, zcu)); + const int_info = lhs_ty.intInfo(zcu); + switch (int_info.bits) { + 1...32 => { + if (self.hasFeature(.m)) { + const dest = try self.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty); + + const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register); + defer self.register_manager.unlockReg(add_result_lock); + + const tuple_ty = self.typeOfIndex(inst); + + // TODO: optimization, set this to true. needs the other struct access stuff to support + // accessing registers. + const result_mcv = try self.allocRegOrMem(inst, false); + + const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu)); + const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu)); + + try self.genSetStack(lhs_ty, result_mcv.offset(result_off).load_frame, dest); + + if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { + if (int_info.signedness == .unsigned) { + switch (int_info.bits) { + 1...8 => { + const max_val = std.math.pow(u16, 2, int_info.bits) - 1; + + const overflow_reg, const overflow_lock = try self.allocReg(); + defer self.register_manager.unlockReg(overflow_lock); + + const add_reg, const add_lock = blk: { + if (dest == .register) break :blk .{ dest.register, null }; + + const add_reg, const add_lock = try self.allocReg(); + try self.genSetReg(lhs_ty, add_reg, dest); + break :blk .{ add_reg, add_lock }; + }; + defer if (add_lock) |lock| self.register_manager.unlockReg(lock); + + _ = try self.addInst(.{ + .tag = .andi, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = overflow_reg, + .rs1 = add_reg, + .imm12 = Immediate.s(max_val), + } }, + }); + + const overflow_mcv = try self.binOp( + .cmp_neq, + .{ .register = overflow_reg }, + lhs_ty, + .{ .register = add_reg }, + lhs_ty, + ); + + try self.genSetStack( + lhs_ty, + result_mcv.offset(overflow_off).load_frame, + overflow_mcv, + ); + + break :result result_mcv; + }, + + else => return self.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}), + } + } else { + return self.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{}); + } + } else { + return self.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{}); + } + } else { + return self.fail("TODO: emulate mul for targets without M feature", .{}); + } + }, + else => return self.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}), + } + }, + } + }; + + return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); } fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { @@ -1201,111 +2422,200 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { fn airDiv(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement div for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airRem(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airMod(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mod for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement zcu for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement bitwise and for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement bitwise and for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airBitOr(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement bitwise or for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement bitwise or for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airXor(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement xor for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement xor for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airShl(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.typeOf(bin_op.lhs); + const rhs_ty = self.typeOf(bin_op.rhs); + + break :result try self.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty); + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airShr(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload_ptr_set for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .optional_payload_ptr_set for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch}); + const zcu = self.bin_file.comp.module.?; + const err_union_ty = self.typeOf(ty_op.operand); + const err_ty = err_union_ty.errorUnionSet(zcu); + const payload_ty = err_union_ty.errorUnionPayload(zcu); + const operand = try self.resolveInst(ty_op.operand); + + const result: MCValue = result: { + if (err_ty.errorSetIsEmpty(zcu)) { + break :result .{ .immediate = 0 }; + } + + if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { + break :result operand; + } + + const err_off: u32 = @intCast(errUnionErrorOffset(payload_ty, zcu)); + + switch (operand) { + .register => |reg| { + const eu_lock = self.register_manager.lockReg(reg); + defer if (eu_lock) |lock| self.register_manager.unlockReg(lock); + + var result = try self.copyToNewRegister(inst, operand); + + if (err_off > 0) { + result = try self.binOp( + .shr, + result, + err_union_ty, + .{ .immediate = @as(u6, @intCast(err_off * 8)) }, + Type.u8, + ); + } + break :result result; + }, + else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}), + } + }; + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}); + const operand_ty = self.typeOf(ty_op.operand); + const operand = try self.resolveInst(ty_op.operand); + const result = try self.genUnwrapErrUnionPayloadMir(operand_ty, operand); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn genUnwrapErrUnionPayloadMir( + self: *Self, + err_union_ty: Type, + err_union: MCValue, +) !MCValue { + const zcu = self.bin_file.comp.module.?; + const payload_ty = err_union_ty.errorUnionPayload(zcu); + + const result: MCValue = result: { + if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; + + const payload_off: u31 = @intCast(errUnionPayloadOffset(payload_ty, zcu)); + switch (err_union) { + .load_frame => |frame_addr| break :result .{ .load_frame = .{ + .index = frame_addr.index, + .off = frame_addr.off + payload_off, + } }, + .register => |reg| { + const eu_lock = self.register_manager.lockReg(reg); + defer if (eu_lock) |lock| self.register_manager.unlockReg(lock); + + var result: MCValue = .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) }; + + if (payload_off > 0) { + result = try self.binOp( + .shr, + result, + err_union_ty, + .{ .immediate = @as(u6, @intCast(payload_off * 8)) }, + Type.u8, + ); + } + + break :result result; + }, + else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}), + } + }; + + return result; +} + // *(E!T) -> E fn airUnwrapErrErrPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union error ptr for {}", .{self.target.cpu.arch}); + 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}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } // *(E!T) -> *T fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union payload ptr for {}", .{self.target.cpu.arch}); + 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}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) - .dead + .unreach else return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ .none, .none, .none }); @@ -1323,12 +2633,12 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.comp.module.?; + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const zcu = self.bin_file.comp.module.?; const optional_ty = self.typeOfIndex(inst); // Optional with a zero-bit payload type is just a boolean true - if (optional_ty.abiSize(mod) == 1) + if (optional_ty.abiSize(zcu) == 1) break :result MCValue{ .immediate = 1 }; return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); @@ -1339,72 +2649,251 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { /// T to E!T fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } /// E to E!T fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement wrap errunion error for {}", .{self.target.cpu.arch}); + + const eu_ty = ty_op.ty.toType(); + const pl_ty = eu_ty.errorUnionPayload(zcu); + const err_ty = eu_ty.errorUnionSet(zcu); + + const result: MCValue = result: { + if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result try self.resolveInst(ty_op.operand); + + const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu)); + const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); + const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); + try self.genSetStack(pl_ty, .{ .index = frame_index, .off = pl_off }, .undef); + const operand = try self.resolveInst(ty_op.operand); + try self.genSetStack(err_ty, .{ .index = frame_index, .off = err_off }, operand); + break :result .{ .load_frame = .{ .index = frame_index } }; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airTry(self: *Self, inst: Air.Inst.Index) !void { + const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; + const extra = self.air.extraData(Air.Try, pl_op.payload); + const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); + const operand_ty = self.typeOf(pl_op.operand); + const result = try self.genTry(inst, pl_op.operand, body, operand_ty, false); + return self.finishAir(inst, result, .{ .none, .none, .none }); +} + +fn genTry( + self: *Self, + inst: Air.Inst.Index, + operand: Air.Inst.Ref, + body: []const Air.Inst.Index, + operand_ty: Type, + operand_is_ptr: bool, +) !MCValue { + _ = operand_is_ptr; + + const liveness_cond_br = self.liveness.getCondBr(inst); + + const operand_mcv = try self.resolveInst(operand); + const is_err_mcv = try self.isErr(null, operand_ty, operand_mcv); + + // A branch to the false section. Uses beq. 1 is the default "true" state. + const reloc = try self.condBr(Type.anyerror, is_err_mcv); + + if (self.liveness.operandDies(inst, 0)) { + if (operand.toIndex()) |operand_inst| try self.processDeath(operand_inst); + } + + self.scope_generation += 1; + const state = try self.saveState(); + + for (liveness_cond_br.else_deaths) |death| try self.processDeath(death); + try self.genBody(body); + try self.restoreState(state, &.{}, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); + + self.performReloc(reloc); + + for (liveness_cond_br.then_deaths) |death| try self.processDeath(death); + + const result = if (self.liveness.isUnused(inst)) + .unreach + else + try self.genUnwrapErrUnionPayloadMir(operand_ty, operand_mcv); + + return result; +} + fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch}); + const result = result: { + const src_mcv = try self.resolveInst(ty_op.operand); + if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; + + const dst_mcv = try self.allocRegOrMem(inst, true); + const dst_ty = self.typeOfIndex(inst); + try self.genCopy(dst_ty, dst_mcv, src_mcv); + break :result dst_mcv; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const src_mcv = try self.resolveInst(ty_op.operand); + switch (src_mcv) { + .load_frame => |frame_addr| { + const len_mcv: MCValue = .{ .load_frame = .{ + .index = frame_addr.index, + .off = frame_addr.off + 8, + } }; + if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; + + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(Type.usize, dst_mcv, len_mcv); + break :result dst_mcv; + }, + .register_pair => |pair| { + const len_mcv: MCValue = .{ .register = pair[1] }; + + if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv; + + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(Type.usize, dst_mcv, len_mcv); + break :result dst_mcv; + }, + else => return self.fail("TODO airSliceLen for {}", .{src_mcv}), + } + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const is_volatile = false; // TODO const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch}); + + if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir( + inst, + .unreach, + .{ bin_op.lhs, bin_op.rhs, .none }, + ); + const result: MCValue = result: { + const slice_mcv = try self.resolveInst(bin_op.lhs); + const index_mcv = try self.resolveInst(bin_op.rhs); + + const slice_ty = self.typeOf(bin_op.lhs); + + const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu); + + const index_lock: ?RegisterLock = if (index_mcv == .register) + self.register_manager.lockRegAssumeUnused(index_mcv.register) + else + null; + defer if (index_lock) |reg| self.register_manager.unlockReg(reg); + + const base_mcv: MCValue = switch (slice_mcv) { + .load_frame, + .load_symbol, + => .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, slice_mcv) }, + else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), + }; + + const dest = try self.allocRegOrMem(inst, true); + const addr = try self.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize); + try self.load(dest, addr, slice_ptr_field_type); + + break :result dest; + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); } fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const array_ty = self.typeOf(bin_op.lhs); + const array_mcv = try self.resolveInst(bin_op.lhs); + + const index_mcv = try self.resolveInst(bin_op.rhs); + const index_ty = self.typeOf(bin_op.rhs); + + const elem_ty = array_ty.childType(zcu); + const elem_abi_size = elem_ty.abiSize(zcu); + + const addr_reg, const addr_reg_lock = try self.allocReg(); + defer self.register_manager.unlockReg(addr_reg_lock); + + switch (array_mcv) { + .register => { + const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, zcu)); + try self.genSetStack(array_ty, .{ .index = frame_index }, array_mcv); + try self.genSetReg(Type.usize, addr_reg, .{ .lea_frame = .{ .index = frame_index } }); + }, + .load_frame => |frame_addr| { + try self.genSetReg(Type.usize, addr_reg, .{ .lea_frame = frame_addr }); + }, + else => try self.genSetReg(Type.usize, addr_reg, array_mcv.address()), + } + + const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size); + const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg); + defer self.register_manager.unlockReg(offset_lock); + + const dst_mcv = try self.allocRegOrMem(inst, false); + _ = try self.addInst(.{ + .tag = .add, + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = addr_reg, + .rs1 = offset_reg, + .rs2 = addr_reg, + } }, + }); + try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); + break :result dst_mcv; + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = false; // TODO const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_val for {}", .{self.target.cpu.arch}); + 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}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); } @@ -1417,124 +2906,234 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airGetUnionTag for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airGetUnionTag for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airClz(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airClz for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airClz for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airCtz(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCtz for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.typeOf(ty_op.operand); + + const dest_reg = try self.register_manager.allocReg(inst, gp); + + const source_reg, const source_lock = blk: { + if (operand == .register) break :blk .{ operand.register, null }; + + const source_reg, const source_lock = try self.allocReg(); + try self.genSetReg(operand_ty, source_reg, operand); + break :blk .{ source_reg, source_lock }; + }; + defer if (source_lock) |lock| self.register_manager.unlockReg(lock); + + // TODO: the B extension for RISCV should have the ctz instruction, and we should use it. + + try self.ctz(source_reg, dest_reg, operand_ty); + + break :result .{ .register = dest_reg }; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn ctz(self: *Self, src: Register, dst: Register, ty: Type) !void { + const zcu = self.bin_file.comp.module.?; + const length = (ty.abiSize(zcu) * 8) - 1; + + const count_reg, const count_lock = try self.allocReg(); + defer self.register_manager.unlockReg(count_lock); + + const len_reg, const len_lock = try self.allocReg(); + defer self.register_manager.unlockReg(len_lock); + + try self.genSetReg(Type.usize, count_reg, .{ .immediate = 0 }); + try self.genSetReg(Type.usize, len_reg, .{ .immediate = length }); + + _ = src; + _ = dst; + + return self.fail("TODO: finish ctz", .{}); +} + fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airAbs(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airAbs for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const ty = self.typeOf(ty_op.operand); + const scalar_ty = ty.scalarType(zcu); + const operand = try self.resolveInst(ty_op.operand); + + switch (scalar_ty.zigTypeTag(zcu)) { + .Int => if (ty.zigTypeTag(zcu) == .Vector) { + return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)}); + } else { + const int_bits = ty.intInfo(zcu).bits; + + if (int_bits > 32) { + return self.fail("TODO: airAbs for larger than 32 bits", .{}); + } + + // promote the src into a register + const src_mcv = try self.copyToNewRegister(inst, operand); + // temp register for shift + const temp_reg = try self.register_manager.allocReg(inst, gp); + + _ = try self.addInst(.{ + .tag = .abs, + .ops = .rri, + .data = .{ + .i_type = .{ + .rs1 = src_mcv.register, + .rd = temp_reg, + .imm12 = Immediate.s(int_bits - 1), + }, + }, + }); + + break :result src_mcv; + }, + else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}), + } + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const zcu = self.bin_file.comp.module.?; + const ty = self.typeOf(ty_op.operand); + const operand = try self.resolveInst(ty_op.operand); + + const int_bits = ty.intInfo(zcu).bits; + + // bytes are no-op + if (int_bits == 8 and self.reuseOperand(inst, ty_op.operand, 0, operand)) { + return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); + } + + const dest_reg = try self.register_manager.allocReg(null, gp); + try self.genSetReg(ty, dest_reg, operand); + + const dest_mcv: MCValue = .{ .register = dest_reg }; + + switch (int_bits) { + 16 => { + const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8); + assert(temp == .register); + _ = try self.addInst(.{ + .tag = .slli, + .ops = .rri, + .data = .{ .i_type = .{ + .imm12 = Immediate.s(8), + .rd = dest_reg, + .rs1 = dest_reg, + } }, + }); + _ = try self.addInst(.{ + .tag = .@"or", + .ops = .rri, + .data = .{ .r_type = .{ + .rd = dest_reg, + .rs1 = dest_reg, + .rs2 = temp.register, + } }, + }); + }, + else => return self.fail("TODO: {d} bits for airByteSwap", .{int_bits}), + } + + break :result dest_mcv; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) - .dead + .unreach else return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ un_op, .none, .none }); } -fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool { +fn reuseOperand( + self: *Self, + inst: Air.Inst.Index, + operand: Air.Inst.Ref, + op_index: Liveness.OperandInt, + mcv: MCValue, +) bool { + return self.reuseOperandAdvanced(inst, operand, op_index, mcv, inst); +} + +fn reuseOperandAdvanced( + self: *Self, + inst: Air.Inst.Index, + operand: Air.Inst.Ref, + op_index: Liveness.OperandInt, + mcv: MCValue, + maybe_tracked_inst: ?Air.Inst.Index, +) bool { if (!self.liveness.operandDies(inst, op_index)) return false; switch (mcv) { - .register => |reg| { - // If it's in the registers table, need to associate the register with the + .register, + .register_pair, + => for (mcv.getRegs()) |reg| { + // If it's in the registers table, need to associate the register(s) with the // new instruction. - if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { + if (maybe_tracked_inst) |tracked_inst| { if (!self.register_manager.isRegFree(reg)) { - self.register_manager.registers[index] = inst; + if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { + self.register_manager.registers[index] = tracked_inst; + } } - } - log.debug("%{d} => {} (reused)", .{ inst, reg }); - }, - .stack_offset => |off| { - log.debug("%{d} => stack offset {d} (reused)", .{ inst, off }); + } else self.register_manager.freeReg(reg); }, + .load_frame => |frame_addr| if (frame_addr.index.isNamed()) return false, else => return false, } // Prevent the operand deaths processing code from deallocating it. self.liveness.clearOperandDeath(inst, op_index); - - // That makes us responsible for doing the rest of the stuff that processDeath would have done. - const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; - branch.inst_table.putAssumeCapacity(operand.toIndex().?, .dead); + const op_inst = operand.toIndex().?; + self.getResolvedInstValue(op_inst).reuse(self, maybe_tracked_inst, op_inst); return true; } -fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { - const mod = self.bin_file.comp.module.?; - const elem_ty = ptr_ty.childType(mod); - switch (ptr) { - .none => unreachable, - .undef => unreachable, - .unreach => unreachable, - .dead => unreachable, - .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), - .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), - .register => { - return self.fail("TODO implement loading from MCValue.register", .{}); - }, - .memory, - .stack_offset, - => { - const reg = try self.register_manager.allocReg(null, gp); - const reg_lock = self.register_manager.lockRegAssumeUnused(reg); - defer self.register_manager.unlockReg(reg_lock); - - try self.genSetReg(ptr_ty, reg, ptr); - try self.load(dst_mcv, .{ .register = reg }, ptr_ty); - }, - } -} - fn airLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.comp.module.?; + const zcu = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const elem_ty = self.typeOfIndex(inst); const result: MCValue = result: { - if (!elem_ty.hasRuntimeBits(mod)) - break :result MCValue.none; + if (!elem_ty.hasRuntimeBits(zcu)) + break :result .none; const ptr = try self.resolveInst(ty_op.operand); - const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(mod); + const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(zcu); if (self.liveness.isUnused(inst) and !is_volatile) - break :result MCValue.dead; + break :result .unreach; const dst_mcv: MCValue = blk: { if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) { @@ -1544,35 +3143,47 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { break :blk try self.allocRegOrMem(inst, true); } }; + try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand)); break :result dst_mcv; }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } -fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void { - _ = ptr_ty; +fn load(self: *Self, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerError!void { + const zcu = self.bin_file.comp.module.?; + const dst_ty = ptr_ty.childType(zcu); - switch (ptr) { - .none => unreachable, - .undef => unreachable, - .unreach => unreachable, - .dead => unreachable, - .immediate => |imm| { - try self.setRegOrMem(value_ty, .{ .memory = imm }, value); - }, - .ptr_stack_offset => |off| { - try self.genSetStack(value_ty, off, value); - }, - .register => { - return self.fail("TODO implement storing to MCValue.register", .{}); - }, - .memory => { - return self.fail("TODO implement storing to MCValue.memory", .{}); - }, - .stack_offset => { - return self.fail("TODO implement storing to MCValue.stack_offset", .{}); + log.debug("loading {}:{} into {}", .{ ptr_mcv, ptr_ty.fmt(zcu), dst_mcv }); + + switch (ptr_mcv) { + .none, + .undef, + .unreach, + .dead, + .register_pair, + .reserved_frame, + => unreachable, // not a valid pointer + + .immediate, + .register, + .register_offset, + .lea_frame, + .lea_symbol, + => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()), + + .memory, + .indirect, + .load_symbol, + .load_frame, + => { + const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); + const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); + defer self.register_manager.unlockReg(addr_lock); + + try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); }, + .air_ref => |ptr_ref| try self.load(dst_mcv, try self.resolveInst(ptr_ref), ptr_ty), } } @@ -1590,33 +3201,186 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { try self.store(ptr, value, ptr_ty, value_ty); - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); + return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); +} + +/// Loads `value` into the "payload" of `pointer`. +fn store(self: *Self, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty: Type) !void { + const zcu = self.bin_file.comp.module.?; + + log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(zcu), ptr_mcv, ptr_ty.fmt(zcu) }); + + switch (ptr_mcv) { + .none => unreachable, + .undef => unreachable, + .unreach => unreachable, + .dead => unreachable, + .register_pair => unreachable, + .reserved_frame => unreachable, + + .immediate, + .register, + .register_offset, + .lea_symbol, + .lea_frame, + => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv), + + .memory, + .indirect, + .load_symbol, + .load_frame, + => { + const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); + const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); + defer self.register_manager.unlockReg(addr_lock); + + try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv); + }, + .air_ref => |ptr_ref| try self.store(try self.resolveInst(ptr_ref), src_mcv, ptr_ty, src_ty), + } } fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; - return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index); + const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index); + return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); } fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - return self.structFieldPtr(ty_op.operand, ty_op.ty, index); + const result = try self.structFieldPtr(inst, ty_op.operand, index); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } -fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void { - _ = operand; - _ = ty; - _ = index; - return self.fail("TODO implement codegen struct_field_ptr", .{}); - //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); + +fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { + const zcu = self.bin_file.comp.module.?; + const ptr_field_ty = self.typeOfIndex(inst); + const ptr_container_ty = self.typeOf(operand); + const ptr_container_ty_info = ptr_container_ty.ptrInfo(zcu); + const container_ty = ptr_container_ty.childType(zcu); + + const field_offset: i32 = if (zcu.typeToPackedStruct(container_ty)) |struct_obj| + if (ptr_field_ty.ptrInfo(zcu).packed_offset.host_size == 0) + @divExact(zcu.structPackedFieldBitOffset(struct_obj, index) + + ptr_container_ty_info.packed_offset.bit_offset, 8) + else + 0 + else + @intCast(container_ty.structFieldOffset(index, zcu)); + + const src_mcv = try self.resolveInst(operand); + const dst_mcv = if (switch (src_mcv) { + .immediate, .lea_frame => true, + .register, .register_offset => self.reuseOperand(inst, operand, 0, src_mcv), + else => false, + }) src_mcv else try self.copyToNewRegister(inst, src_mcv); + return dst_mcv.offset(field_offset); } fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.comp.module.?; + const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; - _ = extra; - return self.fail("TODO implement codegen struct_field_val", .{}); - //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); + const operand = extra.struct_operand; + const index = extra.field_index; + + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const zcu = self.bin_file.comp.module.?; + const src_mcv = try self.resolveInst(operand); + const struct_ty = self.typeOf(operand); + const field_ty = struct_ty.structFieldType(index, zcu); + if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; + + const field_off: u32 = switch (struct_ty.containerLayout(zcu)) { + .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8), + .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type| + zcu.structPackedFieldBitOffset(struct_type, index) + else + 0, + }; + + switch (src_mcv) { + .dead, .unreach => unreachable, + .register => |src_reg| { + const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg); + defer self.register_manager.unlockReg(src_reg_lock); + + const dst_reg = if (field_off == 0) + (try self.copyToNewRegister(inst, src_mcv)).register + else + try self.copyToTmpRegister(Type.usize, .{ .register = src_reg }); + + const dst_mcv: MCValue = .{ .register = dst_reg }; + const dst_lock = self.register_manager.lockReg(dst_reg); + defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); + + if (field_off > 0) { + _ = try self.addInst(.{ + .tag = .srli, + .ops = .rri, + .data = .{ .i_type = .{ + .imm12 = Immediate.s(@intCast(field_off)), + .rd = dst_reg, + .rs1 = dst_reg, + } }, + }); + + return self.fail("TODO: airStructFieldVal register with field_off > 0", .{}); + } + + break :result if (field_off == 0) dst_mcv else try self.copyToNewRegister(inst, dst_mcv); + }, + .load_frame => { + const field_abi_size: u32 = @intCast(field_ty.abiSize(mod)); + if (field_off % 8 == 0) { + const field_byte_off = @divExact(field_off, 8); + const off_mcv = src_mcv.address().offset(@intCast(field_byte_off)).deref(); + const field_bit_size = field_ty.bitSize(mod); + + if (field_abi_size <= 8) { + const int_ty = try mod.intType( + if (field_ty.isAbiInt(mod)) field_ty.intInfo(mod).signedness else .unsigned, + @intCast(field_bit_size), + ); + + const dst_reg, const dst_lock = try self.allocReg(); + const dst_mcv = MCValue{ .register = dst_reg }; + defer self.register_manager.unlockReg(dst_lock); + + try self.genCopy(int_ty, dst_mcv, off_mcv); + break :result try self.copyToNewRegister(inst, dst_mcv); + } + + const container_abi_size: u32 = @intCast(struct_ty.abiSize(mod)); + const dst_mcv = if (field_byte_off + field_abi_size <= container_abi_size and + self.reuseOperand(inst, operand, 0, src_mcv)) + off_mcv + else dst: { + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(field_ty, dst_mcv, off_mcv); + break :dst dst_mcv; + }; + if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) { + const tmp_reg, const tmp_lock = try self.allocReg(); + defer self.register_manager.unlockReg(tmp_lock); + + const hi_mcv = + dst_mcv.address().offset(@intCast(field_bit_size / 64 * 8)).deref(); + try self.genSetReg(Type.usize, tmp_reg, hi_mcv); + try self.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg }); + } + break :result dst_mcv; + } + + return self.fail("TODO: airStructFieldVal load_frame field_off non multiple of 8", .{}); + }, + else => return self.fail("TODO: airStructField {s}", .{@tagName(src_mcv)}), + } + }; + + return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); } fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { @@ -1625,18 +3389,18 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { } fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { - const mod = self.bin_file.comp.module.?; + const zcu = self.bin_file.comp.module.?; const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; const ty = arg.ty.toType(); - const owner_decl = mod.funcOwnerDeclIndex(self.func_index); - const name = mod.getParamName(self.func_index, arg.src_index); + const owner_decl = zcu.funcOwnerDeclIndex(self.func_index); + const name = zcu.getParamName(self.func_index, arg.src_index); switch (self.debug_output) { .dwarf => |dw| switch (mcv) { .register => |reg| try dw.genArgDbgInfo(name, ty, owner_decl, .{ .register = reg.dwarfLocOp(), }), - .stack_offset => {}, + .load_frame => {}, else => {}, }, .plan9 => {}, @@ -1645,35 +3409,53 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { } fn airArg(self: *Self, inst: Air.Inst.Index) !void { - const arg_index = self.arg_index; - self.arg_index += 1; + const zcu = self.bin_file.comp.module.?; + var arg_index = self.arg_index; - const ty = self.typeOfIndex(inst); - _ = ty; + // we skip over args that have no bits + while (self.args[arg_index] == .none) arg_index += 1; + self.arg_index = arg_index + 1; - const result = self.args[arg_index]; - // TODO support stack-only arguments - // TODO Copy registers to the stack - const mcv = result; - try self.genArgDbgInfo(inst, mcv); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const src_mcv = self.args[arg_index]; - if (self.liveness.isUnused(inst)) - return self.finishAirBookkeeping(); + const arg_ty = self.typeOfIndex(inst); - switch (mcv) { - .register => |reg| { - self.register_manager.getRegAssumeFree(reg, inst); - }, - else => {}, - } + const dst_mcv = switch (src_mcv) { + .register => dst: { + const frame = try self.allocFrameIndex(FrameAlloc.init(.{ + .size = Type.usize.abiSize(zcu), + .alignment = Type.usize.abiAlignment(zcu), + })); + const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } }; + try self.genCopy(Type.usize, dst_mcv, src_mcv); + break :dst dst_mcv; + }, + .register_pair => dst: { + const frame = try self.allocFrameIndex(FrameAlloc.init(.{ + .size = Type.usize.abiSize(zcu) * 2, + .alignment = Type.usize.abiAlignment(zcu), + })); + const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } }; + try self.genCopy(arg_ty, dst_mcv, src_mcv); + break :dst dst_mcv; + }, + .load_frame => src_mcv, + else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}), + }; - return self.finishAir(inst, mcv, .{ .none, .none, .none }); + try self.genArgDbgInfo(inst, src_mcv); + break :result dst_mcv; + }; + + return self.finishAir(inst, result, .{ .none, .none, .none }); } fn airTrap(self: *Self) !void { _ = try self.addInst(.{ .tag = .unimp, - .data = .{ .nop = {} }, + .ops = .none, + .data = undefined, }); return self.finishAirBookkeeping(); } @@ -1681,19 +3463,22 @@ fn airTrap(self: *Self) !void { fn airBreakpoint(self: *Self) !void { _ = try self.addInst(.{ .tag = .ebreak, - .data = .{ .nop = {} }, + .ops = .none, + .data = undefined, }); return self.finishAirBookkeeping(); } fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void { - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airRetAddr for riscv64", .{}); - return self.finishAir(inst, result, .{ .none, .none, .none }); + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } }); + return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); } fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void { - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFrameAddress for riscv64", .{}); - return self.finishAir(inst, result, .{ .none, .none, .none }); + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } }); + return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); } fn airFence(self: *Self) !void { @@ -1702,152 +3487,257 @@ fn airFence(self: *Self) !void { } fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { - const mod = self.bin_file.comp.module.?; if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const fn_ty = self.typeOf(pl_op.operand); const callee = pl_op.operand; const extra = self.air.extraData(Air.Call, pl_op.payload); - const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]); + const arg_refs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]); - var info = try self.resolveCallingConventionValues(fn_ty); - defer info.deinit(self); + const expected_num_args = 8; + const ExpectedContents = extern struct { + vals: [expected_num_args][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)), + }; + var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = + std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); + const allocator = stack.get(); + + const arg_tys = try allocator.alloc(Type, arg_refs.len); + defer allocator.free(arg_tys); + for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = self.typeOf(arg_ref); + + const arg_vals = try allocator.alloc(MCValue, arg_refs.len); + defer allocator.free(arg_vals); + for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref }; + + const call_ret = try self.genCall(.{ .air = callee }, arg_tys, arg_vals); + + var bt = self.liveness.iterateBigTomb(inst); + try self.feed(&bt, pl_op.operand); + for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref); + + const result = if (self.liveness.isUnused(inst)) .unreach else call_ret; + return self.finishAirResult(inst, result); +} + +fn genCall( + self: *Self, + info: union(enum) { + air: Air.Inst.Ref, + lib: struct { + return_type: InternPool.Index, + param_types: []const InternPool.Index, + lib: ?[]const u8 = null, + callee: []const u8, + }, + }, + arg_tys: []const Type, + args: []const MCValue, +) !MCValue { + const zcu = self.bin_file.comp.module.?; + + const fn_ty = switch (info) { + .air => |callee| fn_info: { + const callee_ty = self.typeOf(callee); + break :fn_info switch (callee_ty.zigTypeTag(zcu)) { + .Fn => callee_ty, + .Pointer => callee_ty.childType(zcu), + else => unreachable, + }; + }, + .lib => |lib| try zcu.funcType(.{ + .param_types = lib.param_types, + .return_type = lib.return_type, + .cc = .C, + }), + }; + + const fn_info = zcu.typeToFunc(fn_ty).?; + var call_info = try self.resolveCallingConventionValues(fn_info); + defer call_info.deinit(self); + + // We need a properly aligned and sized call frame to be able to call this function. + { + const needed_call_frame = FrameAlloc.init(.{ + .size = call_info.stack_byte_count, + .alignment = call_info.stack_align, + }); + const frame_allocs_slice = self.frame_allocs.slice(); + const stack_frame_size = + &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; + stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); + const stack_frame_align = + &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; + stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); + } + + for (call_info.args, 0..) |mc_arg, arg_i| try self.genCopy(arg_tys[arg_i], mc_arg, args[arg_i]); // Due to incremental compilation, how function calls are generated depends // on linking. - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - for (info.args, 0..) |mc_arg, arg_i| { - const arg = args[arg_i]; - const arg_ty = self.typeOf(arg); - const arg_mcv = try self.resolveInst(args[arg_i]); + switch (info) { + .air => |callee| { + if (try self.air.value(callee, zcu)) |func_value| { + const func_key = zcu.intern_pool.indexToKey(func_value.ip_index); + switch (switch (func_key) { + else => func_key, + .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { + .decl => |decl| zcu.intern_pool.indexToKey(zcu.declPtr(decl).val.toIntern()), + else => func_key, + } else func_key, + }) { + .func => |func| { + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); + const sym = elf_file.symbol(sym_index); - switch (mc_arg) { - .none => continue, - .undef => unreachable, - .immediate => unreachable, - .unreach => unreachable, - .dead => unreachable, - .memory => unreachable, - .register => |reg| { - try self.register_manager.getReg(reg, null); - try self.genSetReg(arg_ty, reg, arg_mcv); - }, - .stack_offset => { - return self.fail("TODO implement calling with parameters in memory", .{}); - }, - .ptr_stack_offset => { - return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); - }, - } - } + _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); + const got_addr = sym.zigGotAddress(elf_file); + try self.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) }); - if (try self.air.value(callee, mod)) |func_value| { - switch (mod.intern_pool.indexToKey(func_value.ip_index)) { - .func => |func| { - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); - const sym = elf_file.symbol(sym_index); - _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); - const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file)); - try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr }); - _ = try self.addInst(.{ - .tag = .jalr, - .data = .{ .i_type = .{ - .rd = .ra, - .rs1 = .ra, - .imm12 = 0, - } }, - }); - }, - .extern_func => { - return self.fail("TODO implement calling extern functions", .{}); - }, - else => { - return self.fail("TODO implement calling bitcasted functions", .{}); - }, - } - } else { - return self.fail("TODO implement calling runtime-known function pointer", .{}); - } - } else if (self.bin_file.cast(link.File.Coff)) |_| { - return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch}); - } else if (self.bin_file.cast(link.File.MachO)) |_| { - unreachable; // unsupported architecture for MachO - } else if (self.bin_file.cast(link.File.Plan9)) |_| { - return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}); - } else unreachable; - - const result: MCValue = result: { - switch (info.return_value) { - .register => |reg| { - if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) { - // Save function return value in a callee saved register - break :result try self.copyToNewRegister(inst, info.return_value); + _ = try self.addInst(.{ + .tag = .jalr, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = .ra, + .rs1 = .ra, + .imm12 = Immediate.s(0), + } }, + }); + } else unreachable; + }, + .extern_func => return self.fail("TODO: extern func calls", .{}), + else => return self.fail("TODO implement calling bitcasted functions", .{}), } - }, - else => {}, - } - break :result info.return_value; - }; + } else { + assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer); + const addr_reg, const addr_lock = try self.allocReg(); + defer self.register_manager.unlockReg(addr_lock); + try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee }); + _ = try self.addInst(.{ + .tag = .jalr, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = .ra, + .rs1 = addr_reg, + .imm12 = Immediate.s(0), + } }, + }); + } + }, + .lib => return self.fail("TODO: lib func calls", .{}), + } - if (args.len <= Liveness.bpi - 2) { - var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); - buf[0] = callee; - @memcpy(buf[1..][0..args.len], args); - return self.finishAir(inst, result, buf); - } - var bt = try self.iterateBigTomb(inst, 1 + args.len); - bt.feed(callee); - for (args) |arg| { - bt.feed(arg); - } - return bt.finishAir(result); + return call_info.return_value.short; } -fn ret(self: *Self, mcv: MCValue) !void { - const mod = self.bin_file.comp.module.?; - const ret_ty = self.fn_type.fnReturnType(mod); - try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); - // Just add space for an instruction, patch this later - const index = try self.addInst(.{ - .tag = .nop, - .data = .{ .nop = {} }, - }); - try self.exitlude_jump_relocs.append(self.gpa, index); -} - -fn airRet(self: *Self, inst: Air.Inst.Index) !void { +fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void { + const zcu = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const operand = try self.resolveInst(un_op); - try self.ret(operand); - return self.finishAir(inst, .dead, .{ un_op, .none, .none }); + + if (safety) { + // safe + } else { + // not safe + } + + const ret_ty = self.fn_type.fnReturnType(zcu); + switch (self.ret_mcv.short) { + .none => {}, + .register, + .register_pair, + => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }), + .indirect => |reg_off| { + try self.register_manager.getReg(reg_off.reg, null); + const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); + defer self.register_manager.unlockReg(lock); + + try self.genSetReg(Type.usize, reg_off.reg, self.ret_mcv.long); + try self.genCopy( + ret_ty, + .{ .register_offset = reg_off }, + .{ .air_ref = un_op }, + ); + }, + else => unreachable, + } + + self.ret_mcv.liveOut(self, inst); + try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); + + // Just add space for an instruction, reloced this later + const index = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_j, + .data = .{ .inst = undefined }, + }); + + try self.exitlude_jump_relocs.append(self.gpa, index); } fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ptr = try self.resolveInst(un_op); - _ = ptr; - return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch}); - //return self.finishAir(inst, .dead, .{ un_op, .none, .none }); + + const ptr_ty = self.typeOf(un_op); + switch (self.ret_mcv.short) { + .none => {}, + .register, .register_pair => try self.load(self.ret_mcv.short, ptr, ptr_ty), + .indirect => |reg_off| try self.genSetReg(ptr_ty, reg_off.reg, ptr), + else => unreachable, + } + self.ret_mcv.liveOut(self, inst); + try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); + + // Just add space for an instruction, reloced this later + const index = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_j, + .data = .{ .inst = undefined }, + }); + + try self.exitlude_jump_relocs.append(self.gpa, index); } -fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { +fn airCmp(self: *Self, inst: Air.Inst.Index) !void { + const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - if (self.liveness.isUnused(inst)) - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - const ty = self.typeOf(bin_op.lhs); - const mod = self.bin_file.comp.module.?; - assert(ty.eql(self.typeOf(bin_op.rhs), mod)); - if (ty.zigTypeTag(mod) == .ErrorSet) - return self.fail("TODO implement cmp for errors", .{}); + const zcu = self.bin_file.comp.module.?; - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - _ = op; - _ = lhs; - _ = rhs; + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.typeOf(bin_op.lhs); - return self.fail("TODO implement cmp for {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); + const int_ty = switch (lhs_ty.zigTypeTag(zcu)) { + .Vector => unreachable, // Handled by cmp_vector. + .Enum => lhs_ty.intTagType(zcu), + .Int => lhs_ty, + .Bool => Type.u1, + .Pointer => Type.usize, + .ErrorSet => Type.u16, + .Optional => blk: { + const payload_ty = lhs_ty.optionalChild(zcu); + if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { + break :blk Type.u1; + } else if (lhs_ty.isPtrLikeOptional(zcu)) { + break :blk Type.usize; + } else { + return self.fail("TODO riscv cmp non-pointer optionals", .{}); + } + }, + .Float => return self.fail("TODO riscv cmp floats", .{}), + else => unreachable, + }; + + const int_info = int_ty.intInfo(zcu); + if (int_info.bits <= 64) { + break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty); + } else { + return self.fail("TODO riscv cmp for ints > 64 bits", .{}); + } + }; + + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { @@ -1859,7 +3749,7 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); _ = operand; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -1867,8 +3757,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; _ = try self.addInst(.{ - .tag = .dbg_line, - .data = .{ .dbg_line_column = .{ + .tag = .pseudo, + .ops = .pseudo_dbg_line_column, + .data = .{ .pseudo_dbg_line_column = .{ .line = dbg_stmt.line, .column = dbg_stmt.column, } }, @@ -1878,62 +3769,126 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { } fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); - const func = mod.funcInfo(extra.data.func); - // TODO emit debug info for function change - _ = func; try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len])); } fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const name = self.air.nullTerminatedString(pl_op.payload); const operand = pl_op.operand; - // TODO emit debug info for this variable - _ = name; - return self.finishAir(inst, .dead, .{ operand, .none, .none }); + const ty = self.typeOf(operand); + const mcv = try self.resolveInst(operand); + + const name = self.air.nullTerminatedString(pl_op.payload); + + const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; + try self.genVarDbgInfo(tag, ty, mcv, name); + + return self.finishAir(inst, .unreach, .{ operand, .none, .none }); +} + +fn genVarDbgInfo( + self: Self, + tag: Air.Inst.Tag, + ty: Type, + mcv: MCValue, + name: [:0]const u8, +) !void { + const zcu = self.bin_file.comp.module.?; + const is_ptr = switch (tag) { + .dbg_var_ptr => true, + .dbg_var_val => false, + else => unreachable, + }; + + switch (self.debug_output) { + .dwarf => |dw| { + const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { + .register => |reg| .{ .register = reg.dwarfLocOp() }, + .memory => |address| .{ .memory = address }, + .load_symbol => |sym_off| loc: { + assert(sym_off.off == 0); + break :loc .{ .linker_load = .{ .type = .direct, .sym_index = sym_off.sym } }; + }, + .immediate => |x| .{ .immediate = x }, + .undef => .undef, + .none => .none, + else => blk: { + // log.warn("TODO generate debug info for {}", .{mcv}); + break :blk .nop; + }, + }; + try dw.genVarDbgInfo(name, ty, zcu.funcOwnerDeclIndex(self.func_index), is_ptr, loc); + }, + .plan9 => {}, + .none => {}, + } } fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { - _ = inst; + const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; + const cond = try self.resolveInst(pl_op.operand); + const cond_ty = self.typeOf(pl_op.operand); + const extra = self.air.extraData(Air.CondBr, pl_op.payload); + const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.then_body_len]); + const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]); + const liveness_cond_br = self.liveness.getCondBr(inst); - return self.fail("TODO implement condbr {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); + // If the condition dies here in this condbr instruction, process + // that death now instead of later as this has an effect on + // whether it needs to be spilled in the branches + if (self.liveness.operandDies(inst, 0)) { + if (pl_op.operand.toIndex()) |op_inst| try self.processDeath(op_inst); + } + + self.scope_generation += 1; + const state = try self.saveState(); + const reloc = try self.condBr(cond_ty, cond); + + for (liveness_cond_br.then_deaths) |death| try self.processDeath(death); + try self.genBody(then_body); + try self.restoreState(state, &.{}, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); + + self.performReloc(reloc); + + for (liveness_cond_br.else_deaths) |death| try self.processDeath(death); + try self.genBody(else_body); + try self.restoreState(state, &.{}, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); + + // We already took care of pl_op.operand earlier, so there's nothing left to do. + self.finishAirBookkeeping(); } -fn isNull(self: *Self, operand: MCValue) !MCValue { - _ = operand; - // Here you can specialize this instruction if it makes sense to, otherwise the default - // will call isNonNull and invert the result. - return self.fail("TODO call isNonNull and invert the result", .{}); -} +fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index { + const cond_reg = try self.copyToTmpRegister(cond_ty, condition); -fn isNonNull(self: *Self, operand: MCValue) !MCValue { - _ = operand; - // Here you can specialize this instruction if it makes sense to, otherwise the default - // will call isNull and invert the result. - return self.fail("TODO call isNull and invert the result", .{}); -} - -fn isErr(self: *Self, operand: MCValue) !MCValue { - _ = operand; - // Here you can specialize this instruction if it makes sense to, otherwise the default - // will call isNonNull and invert the result. - return self.fail("TODO call isNonErr and invert the result", .{}); -} - -fn isNonErr(self: *Self, operand: MCValue) !MCValue { - _ = operand; - // Here you can specialize this instruction if it makes sense to, otherwise the default - // will call isNull and invert the result. - return self.fail("TODO call isErr and invert the result", .{}); + return try self.addInst(.{ + .tag = .beq, + .ops = .rr_inst, + .data = .{ + .b_type = .{ + .rs1 = cond_reg, + .rs2 = .zero, + .inst = undefined, + }, + }, + }); } fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand = try self.resolveInst(un_op); break :result try self.isNull(operand); }; @@ -1942,7 +3897,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand_ptr = try self.resolveInst(un_op); const operand: MCValue = blk: { if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { @@ -1958,18 +3913,32 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ un_op, .none, .none }); } +fn isNull(self: *Self, operand: MCValue) !MCValue { + _ = operand; + // Here you can specialize this instruction if it makes sense to, otherwise the default + // will call isNonNull and invert the result. + return self.fail("TODO call isNonNull and invert the result", .{}); +} + fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand = try self.resolveInst(un_op); break :result try self.isNonNull(operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } +fn isNonNull(self: *Self, operand: MCValue) !MCValue { + _ = operand; + // Here you can specialize this instruction if it makes sense to, otherwise the default + // will call isNull and invert the result. + return self.fail("TODO call isNull and invert the result", .{}); +} + fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand_ptr = try self.resolveInst(un_op); const operand: MCValue = blk: { if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { @@ -1987,16 +3956,18 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand = try self.resolveInst(un_op); - break :result try self.isErr(operand); + const operand_ty = self.typeOf(un_op); + break :result try self.isErr(inst, operand_ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand_ptr = try self.resolveInst(un_op); const operand: MCValue = blk: { if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { @@ -2007,23 +3978,100 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { } }; try self.load(operand, operand_ptr, self.typeOf(un_op)); - break :result try self.isErr(operand); + const operand_ptr_ty = self.typeOf(un_op); + const operand_ty = operand_ptr_ty.childType(zcu); + + break :result try self.isErr(inst, operand_ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } +/// Generates a compare instruction which will indicate if `eu_mcv` is an error. +/// +/// Result is in the return register. +fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { + const zcu = self.bin_file.comp.module.?; + const err_ty = eu_ty.errorUnionSet(zcu); + if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false + + _ = maybe_inst; + + const err_off = errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu); + + switch (eu_mcv) { + .register => |reg| { + const eu_lock = self.register_manager.lockReg(reg); + defer if (eu_lock) |lock| self.register_manager.unlockReg(lock); + + const return_reg = try self.copyToTmpRegister(eu_ty, eu_mcv); + const return_lock = self.register_manager.lockRegAssumeUnused(return_reg); + defer self.register_manager.unlockReg(return_lock); + + var return_mcv: MCValue = .{ .register = return_reg }; + + if (err_off > 0) { + return_mcv = try self.binOp( + .shr, + return_mcv, + eu_ty, + .{ .immediate = @as(u6, @intCast(err_off * 8)) }, + Type.u8, + ); + } + + return_mcv = try self.binOp( + .cmp_neq, + return_mcv, + Type.u16, + .{ .immediate = 0 }, + Type.u16, + ); + + return return_mcv; + }, + else => return self.fail("TODO implement isErr for {}", .{eu_mcv}), + } +} + fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand = try self.resolveInst(un_op); - break :result try self.isNonErr(operand); + const ty = self.typeOf(un_op); + break :result try self.isNonErr(inst, ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } +fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { + const is_err_res = try self.isErr(inst, eu_ty, eu_mcv); + switch (is_err_res) { + .register => |reg| { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_not, + .data = .{ + .rr = .{ + .rd = reg, + .rs = reg, + }, + }, + }); + return is_err_res; + }, + // always false case + .immediate => |imm| { + assert(imm == 0); + return MCValue{ .immediate = @intFromBool(imm == 0) }; + }, + else => unreachable, + } +} + fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { const operand_ptr = try self.resolveInst(un_op); const operand: MCValue = blk: { if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { @@ -2033,8 +4081,11 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { break :blk try self.allocRegOrMem(inst, true); } }; + const operand_ptr_ty = self.typeOf(un_op); + const operand_ty = operand_ptr_ty.childType(zcu); + try self.load(operand, operand_ptr, self.typeOf(un_op)); - break :result try self.isNonErr(operand); + break :result try self.isNonErr(inst, operand_ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -2044,16 +4095,32 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const loop = self.air.extraData(Air.Block, ty_pl.payload); const body: []const Air.Inst.Index = @ptrCast(self.air.extra[loop.end..][0..loop.data.body_len]); - const start_index = self.code.items.len; + + self.scope_generation += 1; + const state = try self.saveState(); + + const jmp_target: Mir.Inst.Index = @intCast(self.mir_instructions.len); try self.genBody(body); - try self.jump(start_index); - return self.finishAirBookkeeping(); + try self.restoreState(state, &.{}, .{ + .emit_instructions = true, + .update_tracking = false, + .resurrect = false, + .close_scope = true, + }); + _ = try self.jump(jmp_target); + + self.finishAirBookkeeping(); } /// Send control flow to the `index` of `self.code`. -fn jump(self: *Self, index: usize) !void { - _ = index; - return self.fail("TODO implement jump for {}", .{self.target.cpu.arch}); +fn jump(self: *Self, index: Mir.Inst.Index) !Mir.Inst.Index { + return self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_j, + .data = .{ + .inst = index, + }, + }); } fn airBlock(self: *Self, inst: Air.Inst.Index) !void { @@ -2063,24 +4130,34 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { } fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void { - try self.blocks.putNoClobber(self.gpa, inst, .{ - // A block is a setup to be able to jump to the end. - .relocs = .{}, - // It also acts as a receptacle for break operands. - // Here we use `MCValue.none` to represent a null value so that the first - // break instruction will choose a MCValue for the block result and overwrite - // this field. Following break instructions will use that MCValue to put their - // block results. - .mcv = MCValue{ .none = {} }, - }); - defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); + // A block is a setup to be able to jump to the end. + const inst_tracking_i = self.inst_tracking.count(); + self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(.unreach)); + + self.scope_generation += 1; + try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() }); + const liveness = self.liveness.getBlock(inst); + // TODO emit debug info lexical block try self.genBody(body); - for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc); + var block_data = self.blocks.fetchRemove(inst).?; + defer block_data.value.deinit(self.gpa); + if (block_data.value.relocs.items.len > 0) { + try self.restoreState(block_data.value.state, liveness.deaths, .{ + .emit_instructions = false, + .update_tracking = true, + .resurrect = true, + .close_scope = true, + }); + for (block_data.value.relocs.items) |reloc| self.performReloc(reloc); + } - const result = self.blocks.getPtr(inst).?.mcv; - return self.finishAir(inst, result, .{ .none, .none, .none }); + if (std.debug.runtime_safety) assert(self.inst_tracking.getIndex(inst).? == inst_tracking_i); + const tracking = &self.inst_tracking.values()[inst_tracking_i]; + if (self.liveness.isUnused(inst)) try tracking.die(self, inst); + self.getValueIfFree(tracking.short, inst); + self.finishAirBookkeeping(); } fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { @@ -2091,66 +4168,109 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { // return self.finishAir(inst, .dead, .{ condition, .none, .none }); } -fn performReloc(self: *Self, reloc: Reloc) !void { - _ = self; - switch (reloc) { - .rel32 => unreachable, - .arm_branch => unreachable, +fn performReloc(self: *Self, inst: Mir.Inst.Index) void { + const tag = self.mir_instructions.items(.tag)[inst]; + const ops = self.mir_instructions.items(.ops)[inst]; + const target: Mir.Inst.Index = @intCast(self.mir_instructions.len); + + switch (tag) { + .bne, + .beq, + => self.mir_instructions.items(.data)[inst].b_type.inst = target, + .jal => self.mir_instructions.items(.data)[inst].j_type.inst = target, + .pseudo => switch (ops) { + .pseudo_j => self.mir_instructions.items(.data)[inst].inst = target, + else => std.debug.panic("TODO: performReloc {s}", .{@tagName(ops)}), + }, + else => std.debug.panic("TODO: performReloc {s}", .{@tagName(tag)}), } } fn airBr(self: *Self, inst: Air.Inst.Index) !void { - const branch = self.air.instructions.items(.data)[@intFromEnum(inst)].br; - try self.br(branch.block_inst, branch.operand); - return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); + const mod = self.bin_file.comp.module.?; + const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br; + + const block_ty = self.typeOfIndex(br.block_inst); + const block_unused = + !block_ty.hasRuntimeBitsIgnoreComptime(mod) or self.liveness.isUnused(br.block_inst); + const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; + const block_data = self.blocks.getPtr(br.block_inst).?; + const first_br = block_data.relocs.items.len == 0; + const block_result = result: { + if (block_unused) break :result .none; + + if (!first_br) try self.getValue(block_tracking.short, null); + const src_mcv = try self.resolveInst(br.operand); + + if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) { + if (first_br) break :result src_mcv; + + try self.getValue(block_tracking.short, br.block_inst); + // .long = .none to avoid merging operand and block result stack frames. + const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv }; + try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*); + for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg); + break :result block_tracking.short; + } + + const dst_mcv = if (first_br) try self.allocRegOrMem(br.block_inst, true) else dst: { + try self.getValue(block_tracking.short, br.block_inst); + break :dst block_tracking.short; + }; + try self.genCopy(block_ty, dst_mcv, try self.resolveInst(br.operand)); + break :result dst_mcv; + }; + + // Process operand death so that it is properly accounted for in the State below. + if (self.liveness.operandDies(inst, 0)) { + if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); + } + + if (first_br) { + block_tracking.* = InstTracking.init(block_result); + try self.saveRetroactiveState(&block_data.state); + } else try self.restoreState(block_data.state, &.{}, .{ + .emit_instructions = true, + .update_tracking = false, + .resurrect = false, + .close_scope = false, + }); + + // Emit a jump with a relocation. It will be patched up after the block ends. + // Leave the jump offset undefined + const jmp_reloc = try self.jump(undefined); + try block_data.relocs.append(self.gpa, jmp_reloc); + + // Stop tracking block result without forgetting tracking info + try self.freeValue(block_tracking.short); + + self.finishAirBookkeeping(); } fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const air_tags = self.air.instructions.items(.tag); _ = air_tags; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement boolean operations for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement boolean operations for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { - const block_data = self.blocks.getPtr(block).?; - - const mod = self.bin_file.comp.module.?; - if (self.typeOf(operand).hasRuntimeBits(mod)) { - const operand_mcv = try self.resolveInst(operand); - const block_mcv = block_data.mcv; - if (block_mcv == .none) { - block_data.mcv = operand_mcv; - } else { - try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv); - } - } - return self.brVoid(block); -} - -fn brVoid(self: *Self, block: Air.Inst.Index) !void { - const block_data = self.blocks.getPtr(block).?; - - // Emit a jump with a relocation. It will be patched up after the block ends. - try block_data.relocs.ensureUnusedCapacity(self.gpa, 1); - - return self.fail("TODO implement brvoid for {}", .{self.target.cpu.arch}); -} - fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Asm, ty_pl.payload); const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0; const clobbers_len: u31 = @truncate(extra.data.flags); var extra_i: usize = extra.end; - const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs: []const Air.Inst.Ref = + @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]); extra_i += outputs.len; const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len]); extra_i += inputs.len; + log.debug("airAsm input: {any}", .{inputs}); + const dead = !is_volatile and self.liveness.isUnused(inst); - const result: MCValue = if (dead) .dead else result: { + const result: MCValue = if (dead) .unreach else result: { if (outputs.len > 1) { return self.fail("TODO implement codegen for asm with more than 1 output", .{}); } @@ -2197,19 +4317,25 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { // for the string, we still use the next u32 for the null terminator. extra_i += clobber.len / 4 + 1; - // TODO honor these + if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) { + // nothing really to do + } else { + try self.register_manager.getReg(parseRegName(clobber) orelse + return self.fail("invalid clobber: '{s}'", .{clobber}), null); + } } } const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; - if (mem.eql(u8, asm_source, "ecall")) { + if (std.meta.stringToEnum(Mir.Inst.Tag, asm_source)) |tag| { _ = try self.addInst(.{ - .tag = .ecall, - .data = .{ .nop = {} }, + .tag = tag, + .ops = .none, + .data = undefined, }); } else { - return self.fail("TODO implement support for more riscv64 assembly instructions", .{}); + return self.fail("TODO: asm_source {s}", .{asm_source}); } if (output_constraint) |output| { @@ -2219,11 +4345,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const reg_name = output[2 .. output.len - 1]; const reg = parseRegName(reg_name) orelse return self.fail("unrecognized register: '{s}'", .{reg_name}); - break :result MCValue{ .register = reg }; + break :result .{ .register = reg }; } else { - break :result MCValue{ .none = {} }; + break :result .{ .none = {} }; } }; + simple: { var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); var buf_index: usize = 0; @@ -2238,51 +4365,292 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { @memcpy(buf[buf_index..][0..inputs.len], inputs); return self.finishAir(inst, result, buf); } - var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len); - for (outputs) |output| { - if (output == .none) continue; - - bt.feed(output); - } - for (inputs) |input| { - bt.feed(input); - } - return bt.finishAir(result); -} - -fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb { - try self.ensureProcessDeathCapacity(operand_count + 1); - return BigTomb{ - .function = self, - .inst = inst, - .lbt = self.liveness.iterateBigTomb(inst), - }; + var bt = self.liveness.iterateBigTomb(inst); + for (outputs) |output| if (output != .none) try self.feed(&bt, output); + for (inputs) |input| try self.feed(&bt, input); + return self.finishAirResult(inst, result); } /// Sets the value without any modifications to register allocation metadata or stack allocation metadata. -fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { - switch (loc) { - .none => return, - .register => |reg| return self.genSetReg(ty, reg, val), - .stack_offset => |off| return self.genSetStack(ty, off, val), - .memory => { - return self.fail("TODO implement setRegOrMem for memory", .{}); +fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { + const zcu = self.bin_file.comp.module.?; + + // There isn't anything to store + if (dst_mcv == .none) return; + + if (!dst_mcv.isMutable()) { + // panic so we can see the trace + return self.fail("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)}); + } + + switch (dst_mcv) { + .register => |reg| return self.genSetReg(ty, reg, src_mcv), + .register_offset => |dst_reg_off| try self.genSetReg(ty, dst_reg_off.reg, switch (src_mcv) { + .none, + .unreach, + .dead, + .undef, + => unreachable, + .immediate, + .register, + .register_offset, + => src_mcv.offset(-dst_reg_off.off), + else => .{ .register_offset = .{ + .reg = try self.copyToTmpRegister(ty, src_mcv), + .off = -dst_reg_off.off, + } }, + }), + .indirect => |ro| { + const src_reg = try self.copyToTmpRegister(ty, src_mcv); + + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_store_rm, + .data = .{ .rm = .{ + .r = src_reg, + .m = .{ + .base = .{ .reg = ro.reg }, + .mod = .{ .rm = .{ .disp = ro.off, .size = self.memSize(ty) } }, + }, + } }, + }); }, - else => unreachable, + .load_frame => |frame| return self.genSetStack(ty, frame, src_mcv), + .memory => return self.fail("TODO: genCopy memory", .{}), + .register_pair => |dst_regs| { + const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) { + .register_pair, .memory, .indirect, .load_frame => null, + .load_symbol => src: { + const src_addr_reg, const src_addr_lock = try self.allocReg(); + errdefer self.register_manager.unlockReg(src_addr_lock); + + try self.genSetReg(Type.usize, src_addr_reg, src_mcv.address()); + break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; + }, + .air_ref => |src_ref| return self.genCopy( + ty, + dst_mcv, + try self.resolveInst(src_ref), + ), + else => unreachable, + }; + defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); + + var part_disp: i32 = 0; + for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| { + try self.genSetReg(dst_ty, dst_reg, switch (src_mcv) { + .register_pair => |src_regs| .{ .register = src_regs[part_i] }, + .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(), + .load_symbol => .{ .indirect = .{ + .reg = src_info.?.addr_reg, + .off = part_disp, + } }, + else => unreachable, + }); + part_disp += @intCast(dst_ty.abiSize(zcu)); + } + }, + else => return self.fail("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }), } } -fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { - _ = ty; - _ = stack_offset; - _ = mcv; - return self.fail("TODO implement getSetStack for {}", .{self.target.cpu.arch}); +fn genSetStack( + self: *Self, + ty: Type, + frame: FrameAddr, + src_mcv: MCValue, +) InnerError!void { + const zcu = self.bin_file.comp.module.?; + const abi_size: u32 = @intCast(ty.abiSize(zcu)); + + switch (src_mcv) { + .none => return, + .dead => unreachable, + .undef => { + if (!self.wantSafety()) return; + try self.genSetStack(ty, frame, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); + }, + .immediate, + .lea_frame, + => { + // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with + // a register allocation. + const reg, const reg_lock = try self.allocReg(); + defer self.register_manager.unlockReg(reg_lock); + + try self.genSetReg(ty, reg, src_mcv); + + return self.genSetStack(ty, frame, .{ .register = reg }); + }, + .register => |reg| { + switch (abi_size) { + 1, 2, 4, 8 => { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_store_rm, + .data = .{ .rm = .{ + .r = reg, + .m = .{ + .base = .{ .frame = frame.index }, + .mod = .{ + .rm = .{ + .size = self.memSize(ty), + .disp = frame.off, + }, + }, + }, + } }, + }); + }, + else => unreachable, // register can hold a max of 8 bytes + } + }, + .register_pair => |pair| { + var part_disp: i32 = frame.off; + for (try self.splitType(ty), pair) |src_ty, src_reg| { + try self.genSetStack( + src_ty, + .{ .index = frame.index, .off = part_disp }, + .{ .register = src_reg }, + ); + part_disp += @intCast(src_ty.abiSize(zcu)); + } + }, + .load_frame, + .indirect, + .load_symbol, + => { + if (abi_size <= 8) { + const reg = try self.copyToTmpRegister(ty, src_mcv); + return self.genSetStack(ty, frame, .{ .register = reg }); + } + + try self.genInlineMemcpy( + .{ .lea_frame = frame }, + src_mcv.address(), + .{ .immediate = abi_size }, + ); + }, + .air_ref => |ref| try self.genSetStack(ty, frame, try self.resolveInst(ref)), + else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_mcv)}), + } } -fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { - switch (mcv) { +fn genInlineMemcpy( + self: *Self, + dst_ptr: MCValue, + src_ptr: MCValue, + len: MCValue, +) !void { + const regs = try self.register_manager.allocRegs(4, .{null} ** 4, tp); + const locks = self.register_manager.lockRegsAssumeUnused(4, regs); + defer for (locks) |lock| self.register_manager.unlockReg(lock); + + const count = regs[0]; + const tmp = regs[1]; + const src = regs[2]; + const dst = regs[3]; + + try self.genSetReg(Type.usize, count, len); + try self.genSetReg(Type.usize, src, src_ptr); + try self.genSetReg(Type.usize, dst, dst_ptr); + + // lb tmp, 0(src) + const first_inst = try self.addInst(.{ + .tag = .lb, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = tmp, + .rs1 = src, + .imm12 = Immediate.s(0), + }, + }, + }); + + // sb tmp, 0(dst) + _ = try self.addInst(.{ + .tag = .sb, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = dst, + .rs1 = tmp, + .imm12 = Immediate.s(0), + }, + }, + }); + + // dec count by 1 + _ = try self.addInst(.{ + .tag = .addi, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = count, + .rs1 = count, + .imm12 = Immediate.s(-1), + }, + }, + }); + + // branch if count is 0 + _ = try self.addInst(.{ + .tag = .beq, + .ops = .rr_inst, + .data = .{ + .b_type = .{ + .inst = @intCast(self.mir_instructions.len + 4), // points after the last inst + .rs1 = count, + .rs2 = .zero, + }, + }, + }); + + // increment the pointers + _ = try self.addInst(.{ + .tag = .addi, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = src, + .rs1 = src, + .imm12 = Immediate.s(1), + }, + }, + }); + + _ = try self.addInst(.{ + .tag = .addi, + .ops = .rri, + .data = .{ + .i_type = .{ + .rd = dst, + .rs1 = dst, + .imm12 = Immediate.s(1), + }, + }, + }); + + // jump back to start of loop + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_j, + .data = .{ + .inst = first_inst, + }, + }); +} + +/// Sets the value of `src_mcv` into `reg`. Assumes you have a lock on it. +fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!void { + const zcu = self.bin_file.comp.module.?; + const abi_size: u32 = @intCast(ty.abiSize(zcu)); + + if (abi_size > 8) return self.fail("tried to set reg with size {}", .{abi_size}); + + switch (src_mcv) { .dead => unreachable, - .ptr_stack_offset => unreachable, .unreach, .none => return, // Nothing to do. .undef => { if (!self.wantSafety()) @@ -2295,10 +4663,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { _ = try self.addInst(.{ .tag = .addi, + .ops = .rri, .data = .{ .i_type = .{ .rd = reg, .rs1 = .zero, - .imm12 = @intCast(x), + .imm12 = Immediate.s(@intCast(x)), } }, }); } else if (math.minInt(i32) <= x and x <= math.maxInt(i32)) { @@ -2306,26 +4675,56 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void const carry: i32 = if (lo12 < 0) 1 else 0; const hi20: i20 = @truncate((x >> 12) +% carry); - // TODO: add test case for 32-bit immediate _ = try self.addInst(.{ .tag = .lui, + .ops = .ri, .data = .{ .u_type = .{ .rd = reg, - .imm20 = hi20, + .imm20 = Immediate.s(hi20), } }, }); _ = try self.addInst(.{ .tag = .addi, + .ops = .rri, .data = .{ .i_type = .{ .rd = reg, .rs1 = reg, - .imm12 = lo12, + .imm12 = Immediate.s(lo12), } }, }); } else { - // li rd, immediate - // "Myriad sequences" - return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf + // TODO: use a more advanced myriad seq to do this without a reg. + // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L224 + + const temp, const temp_lock = try self.allocReg(); + defer self.register_manager.unlockReg(temp_lock); + + const lo32: i32 = @truncate(x); + const carry: i32 = if (lo32 < 0) 1 else 0; + const hi32: i32 = @truncate((x >> 32) +% carry); + + try self.genSetReg(Type.i32, temp, .{ .immediate = @bitCast(@as(i64, lo32)) }); + try self.genSetReg(Type.i32, reg, .{ .immediate = @bitCast(@as(i64, hi32)) }); + + _ = try self.addInst(.{ + .tag = .slli, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = reg, + .rs1 = reg, + .imm12 = Immediate.s(32), + } }, + }); + + _ = try self.addInst(.{ + .tag = .add, + .ops = .rrr, + .data = .{ .r_type = .{ + .rd = reg, + .rs1 = reg, + .rs2 = temp, + } }, + }); } }, .register => |src_reg| { @@ -2335,62 +4734,160 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void // mov reg, src_reg _ = try self.addInst(.{ - .tag = .mv, + .tag = .pseudo, + .ops = .pseudo_mv, .data = .{ .rr = .{ .rd = reg, .rs = src_reg, } }, }); }, + .register_pair => |pair| try self.genSetReg(ty, reg, .{ .register = pair[0] }), .memory => |addr| { - // The value is in memory at a hard-coded address. - // If the type is a pointer, it means the pointer address is at this memory location. try self.genSetReg(ty, reg, .{ .immediate = addr }); _ = try self.addInst(.{ .tag = .ld, + .ops = .rri, .data = .{ .i_type = .{ .rd = reg, .rs1 = reg, - .imm12 = 0, + .imm12 = Immediate.s(0), } }, }); - // LOAD imm=[i12 offset = 0], rs1 = - - // return self.fail("TODO implement genSetReg memory for riscv64"); }, - else => return self.fail("TODO implement getSetReg for riscv64 {}", .{mcv}), + .load_frame => |frame| { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_load_rm, + .data = .{ .rm = .{ + .r = reg, + .m = .{ + .base = .{ .frame = frame.index }, + .mod = .{ + .rm = .{ + .size = self.memSize(ty), + .disp = frame.off, + }, + }, + }, + } }, + }); + }, + .lea_frame => |frame| { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_lea_rm, + .data = .{ .rm = .{ + .r = reg, + .m = .{ + .base = .{ .frame = frame.index }, + .mod = .{ + .rm = .{ + .size = self.memSize(ty), + .disp = frame.off, + }, + }, + }, + } }, + }); + }, + .load_symbol => { + try self.genSetReg(ty, reg, src_mcv.address()); + try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = reg } }); + }, + .indirect => |reg_off| { + const load_tag: Mir.Inst.Tag = switch (abi_size) { + 1 => .lb, + 2 => .lh, + 4 => .lw, + 8 => .ld, + else => return self.fail("TODO: genSetReg for size {d}", .{abi_size}), + }; + + _ = try self.addInst(.{ + .tag = load_tag, + .ops = .rri, + .data = .{ .i_type = .{ + .rd = reg, + .rs1 = reg_off.reg, + .imm12 = Immediate.s(reg_off.off), + } }, + }); + }, + .lea_symbol => |sym_off| { + assert(sym_off.off == 0); + + const atom_index = try self.symbolIndex(); + + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_load_symbol, + .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{ + .register = reg.id(), + .atom_index = atom_index, + .sym_index = sym_off.sym, + }) }, + }); + }, + .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)), + else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}), } } fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const result = try self.resolveInst(un_op); + const result = result: { + const src_mcv = try self.resolveInst(un_op); + if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; + + const dst_mcv = try self.allocRegOrMem(inst, true); + const dst_ty = self.typeOfIndex(inst); + try self.genCopy(dst_ty, dst_mcv, src_mcv); + break :result dst_mcv; + }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; + const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result = if (self.liveness.isUnused(inst)) .dead else result: { - const operand = try self.resolveInst(ty_op.operand); - if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + const result = if (self.liveness.isUnused(inst)) .unreach else result: { + const src_mcv = try self.resolveInst(ty_op.operand); - const operand_lock = switch (operand) { - .register => |reg| self.register_manager.lockReg(reg), - else => null, + const dst_ty = self.typeOfIndex(inst); + const src_ty = self.typeOf(ty_op.operand); + + const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; + defer if (src_lock) |lock| self.register_manager.unlockReg(lock); + + const dst_mcv = if (dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and + self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { + const dst_mcv = try self.allocRegOrMem(inst, true); + try self.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) { + .lt => dst_ty, + .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty, + .gt => src_ty, + }, dst_mcv, src_mcv); + break :dst dst_mcv; }; - defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); - const dest = try self.allocRegOrMem(inst, true); - try self.setRegOrMem(self.typeOfIndex(inst), dest, operand); - break :result dest; + if (dst_ty.isAbiInt(zcu) and src_ty.isAbiInt(zcu) and + dst_ty.intInfo(zcu).signedness == src_ty.intInfo(zcu).signedness) break :result dst_mcv; + + const abi_size = dst_ty.abiSize(zcu); + const bit_size = dst_ty.bitSize(zcu); + if (abi_size * 8 <= bit_size) break :result dst_mcv; + + return self.fail("TODO: airBitCast {} to {}", .{ src_ty.fmt(zcu), dst_ty.fmt(zcu) }); }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airArrayToSlice for {}", .{ + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airArrayToSlice for {}", .{ self.target.cpu.arch, }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -2398,7 +4895,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFloatFromInt for {}", .{ + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airFloatFromInt for {}", .{ self.target.cpu.arch, }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -2406,7 +4903,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airIntFromFloat for {}", .{ + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airIntFromFloat for {}", .{ self.target.cpu.arch, }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -2456,7 +4953,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else { _ = operand; return self.fail("TODO implement airTagName for riscv64", .{}); }; @@ -2464,49 +4961,98 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { } fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { + const zcu = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const operand = try self.resolveInst(un_op); - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { - _ = operand; - return self.fail("TODO implement airErrorName for riscv64", .{}); - }; - return self.finishAir(inst, result, .{ un_op, .none, .none }); + + const err_ty = self.typeOf(un_op); + const err_mcv = try self.resolveInst(un_op); + + const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); + const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); + defer self.register_manager.unlockReg(err_lock); + + const addr_reg, const addr_lock = try self.allocReg(); + defer self.register_manager.unlockReg(addr_lock); + + const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, zcu); + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym = elf_file.symbol(sym_index); + try self.genSetReg(Type.usize, addr_reg, .{ .load_symbol = .{ .sym = sym.esym_index } }); + } else { + return self.fail("TODO: riscv non-elf", .{}); + } + + const start_reg, const start_lock = try self.allocReg(); + defer self.register_manager.unlockReg(start_lock); + + const end_reg, const end_lock = try self.allocReg(); + defer self.register_manager.unlockReg(end_lock); + + _ = start_reg; + _ = end_reg; + + return self.fail("TODO: airErrorName", .{}); } fn airSplat(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSplat for riscv64", .{}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSplat for riscv64", .{}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airSelect(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = self.air.extraData(Air.Bin, pl_op.payload).data; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for riscv64", .{}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSelect for riscv64", .{}); return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); } fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for riscv64", .{}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airShuffle for riscv64", .{}); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airReduce(self: *Self, inst: Air.Inst.Index) !void { const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airReduce for riscv64", .{}); + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airReduce for riscv64", .{}); return self.finishAir(inst, result, .{ reduce.operand, .none, .none }); } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.comp.module.?; - const vector_ty = self.typeOfIndex(inst); - const len = vector_ty.vectorLen(mod); + const zcu = self.bin_file.comp.module.?; + const result_ty = self.typeOfIndex(inst); + const len: usize = @intCast(result_ty.arrayLen(zcu)); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]); - const result: MCValue = res: { - if (self.liveness.isUnused(inst)) break :res MCValue.dead; - return self.fail("TODO implement airAggregateInit for riscv64", .{}); + const result: MCValue = result: { + switch (result_ty.zigTypeTag(zcu)) { + .Struct => { + const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu)); + + if (result_ty.containerLayout(zcu) == .@"packed") {} else for (elements, 0..) |elem, elem_i| { + if ((try result_ty.structFieldValueComptime(zcu, elem_i)) != null) continue; + + const elem_ty = result_ty.structFieldType(elem_i, zcu); + const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu)); + const elem_mcv = try self.resolveInst(elem); + + const elem_frame: FrameAddr = .{ + .index = frame_index, + .off = elem_off, + }; + try self.genSetStack( + elem_ty, + elem_frame, + elem_mcv, + ); + } + }, + else => return self.fail("TODO: airAggregateInit {}", .{result_ty.fmt(zcu)}), + } + break :result .{ .register = .zero }; }; if (elements.len <= Liveness.bpi - 1) { @@ -2514,11 +5060,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { @memcpy(buf[0..elements.len], elements); return self.finishAir(inst, result, buf); } - var bt = try self.iterateBigTomb(inst, elements.len); - for (elements) |elem| { - bt.feed(elem); - } - return bt.finishAir(result); + var bt = self.liveness.iterateBigTomb(inst); + for (elements) |elem| try self.feed(&bt, elem); + return self.finishAirResult(inst, result); } fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { @@ -2531,57 +5075,68 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch; - return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none }); + // TODO: RISC-V does have prefetch instruction variants. + // see here: https://raw.githubusercontent.com/riscv/riscv-CMOs/master/specifications/cmobase-v1.0.1.pdf + return self.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none }); } fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = self.air.extraData(Air.Bin, pl_op.payload).data; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { + const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else { return self.fail("TODO implement airMulAdd for riscv64", .{}); }; return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); } -fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { - const mod = self.bin_file.comp.module.?; +fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { + const zcu = self.bin_file.comp.module.?; // If the type has no codegen bits, no need to store it. - const inst_ty = self.typeOf(inst); - if (!inst_ty.hasRuntimeBits(mod)) - return MCValue{ .none = {} }; + const inst_ty = self.typeOf(ref); + if (!inst_ty.hasRuntimeBits(zcu)) + return .none; - const inst_index = inst.toIndex() orelse return self.genTypedValue((try self.air.value(inst, mod)).?); + const mcv = if (ref.toIndex()) |inst| mcv: { + break :mcv self.inst_tracking.getPtr(inst).?.short; + } else mcv: { + const ip_index = ref.toInterned().?; + const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); + if (!gop.found_existing) gop.value_ptr.* = InstTracking.init( + try self.genTypedValue(Value.fromInterned(ip_index)), + ); + break :mcv gop.value_ptr.short; + }; - return self.getResolvedInstValue(inst_index); + return mcv; } -fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { - // Treat each stack item as a "layer" on top of the previous one. - var i: usize = self.branch_stack.items.len; - while (true) { - i -= 1; - if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| { - assert(mcv != .dead); - return mcv; - } - } +fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking { + const tracking = self.inst_tracking.getPtr(inst).?; + return switch (tracking.short) { + .none, .unreach, .dead => unreachable, + else => tracking, + }; } fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { - const mod = self.bin_file.comp.module.?; - const mcv: MCValue = switch (try codegen.genTypedValue( + const zcu = self.bin_file.comp.module.?; + const result = try codegen.genTypedValue( self.bin_file, self.src_loc, val, - mod.funcOwnerDeclIndex(self.func_index), - )) { + zcu.funcOwnerDeclIndex(self.func_index), + ); + const mcv: MCValue = switch (result) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, - .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO + .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, .immediate => |imm| .{ .immediate = imm }, .memory => |addr| .{ .memory = addr }, + .load_got, .load_direct, .load_tlv => { + return self.fail("TODO: genTypedValue {s}", .{@tagName(mcv)}); + }, }, .fail => |msg| { self.err_msg = msg; @@ -2593,8 +5148,8 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { const CallMCValues = struct { args: []MCValue, - return_value: MCValue, - stack_byte_count: u32, + return_value: InstTracking, + stack_byte_count: u31, stack_align: Alignment, fn deinit(self: *CallMCValues, func: *Self) void { @@ -2604,94 +5159,134 @@ const CallMCValues = struct { }; /// Caller must call `CallMCValues.deinit`. -fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { - const mod = self.bin_file.comp.module.?; - const ip = &mod.intern_pool; - const fn_info = mod.typeToFunc(fn_ty).?; +fn resolveCallingConventionValues( + self: *Self, + fn_info: InternPool.Key.FuncType, +) !CallMCValues { + const zcu = self.bin_file.comp.module.?; + const ip = &zcu.intern_pool; + + const param_types = try self.gpa.alloc(Type, fn_info.param_types.len); + defer self.gpa.free(param_types); + + for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| { + dest.* = Type.fromInterned(src); + } + const cc = fn_info.cc; var result: CallMCValues = .{ - .args = try self.gpa.alloc(MCValue, fn_info.param_types.len), + .args = try self.gpa.alloc(MCValue, param_types.len), // These undefined values must be populated before returning from this function. .return_value = undefined, - .stack_byte_count = undefined, + .stack_byte_count = 0, .stack_align = undefined, }; errdefer self.gpa.free(result.args); - const ret_ty = fn_ty.fnReturnType(mod); + const ret_ty = Type.fromInterned(fn_info.return_type); switch (cc) { .Naked => { assert(result.args.len == 0); - result.return_value = .{ .unreach = {} }; - result.stack_byte_count = 0; - result.stack_align = .@"1"; - return result; + result.return_value = InstTracking.init(.unreach); + result.stack_align = .@"8"; }, - .Unspecified, .C => { - // LP64D ABI - // - // TODO make this generic with other ABIs, in particular - // with different hardware floating-point calling - // conventions - var next_register: usize = 0; - var next_stack_offset: u32 = 0; - // TODO: this is never assigned, which is a bug, but I don't know how this code works - // well enough to try and fix it. I *think* `next_register += next_stack_offset` is - // supposed to be `next_stack_offset += param_size` in every case where it appears. - _ = &next_stack_offset; - - const argument_registers = [_]Register{ .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7 }; - - for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { - const param_size: u32 = @intCast(Type.fromInterned(ty).abiSize(mod)); - if (param_size <= 8) { - if (next_register < argument_registers.len) { - result_arg.* = .{ .register = argument_registers[next_register] }; - next_register += 1; - } else { - result_arg.* = .{ .stack_offset = next_stack_offset }; - next_register += next_stack_offset; - } - } else if (param_size <= 16) { - if (next_register < argument_registers.len - 1) { - return self.fail("TODO MCValues with 2 registers", .{}); - } else if (next_register < argument_registers.len) { - return self.fail("TODO MCValues split register + stack", .{}); - } else { - result_arg.* = .{ .stack_offset = next_stack_offset }; - next_register += next_stack_offset; - } - } else { - result_arg.* = .{ .stack_offset = next_stack_offset }; - next_register += next_stack_offset; - } + .C, .Unspecified => { + if (result.args.len > 8) { + return self.fail("RISC-V calling convention does not support more than 8 arguments", .{}); } - result.stack_byte_count = next_stack_offset; + var ret_int_reg_i: u32 = 0; + var param_int_reg_i: u32 = 0; + result.stack_align = .@"16"; + + // Return values + if (ret_ty.zigTypeTag(zcu) == .NoReturn) { + result.return_value = InstTracking.init(.unreach); + } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) { + result.return_value = InstTracking.init(.none); + } else { + var ret_tracking: [2]InstTracking = undefined; + var ret_tracking_i: usize = 0; + + const classes = mem.sliceTo(&abi.classifySystem(ret_ty, zcu), .none); + + for (classes) |class| switch (class) { + .integer => { + const ret_int_reg = abi.function_ret_regs[ret_int_reg_i]; + ret_int_reg_i += 1; + + ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg }); + ret_tracking_i += 1; + }, + .memory => { + const ret_int_reg = abi.function_ret_regs[ret_int_reg_i]; + ret_int_reg_i += 1; + const ret_indirect_reg = abi.function_arg_regs[param_int_reg_i]; + param_int_reg_i += 1; + + ret_tracking[ret_tracking_i] = .{ + .short = .{ .indirect = .{ .reg = ret_int_reg } }, + .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, + }; + ret_tracking_i += 1; + }, + else => return self.fail("TODO: C calling convention return class {}", .{class}), + }; + + result.return_value = switch (ret_tracking_i) { + else => return self.fail("ty {} took {} tracking return indices", .{ ret_ty.fmt(zcu), ret_tracking_i }), + 1 => ret_tracking[0], + 2 => InstTracking.init(.{ .register_pair = .{ + ret_tracking[0].short.register, ret_tracking[1].short.register, + } }), + }; + } + + for (param_types, result.args) |ty, *arg| { + assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); + + var arg_mcv: [2]MCValue = undefined; + var arg_mcv_i: usize = 0; + + const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none); + + for (classes) |class| switch (class) { + .integer => { + const param_int_regs = abi.function_arg_regs; + if (param_int_reg_i >= param_int_regs.len) break; + + const param_int_reg = param_int_regs[param_int_reg_i]; + param_int_reg_i += 1; + + arg_mcv[arg_mcv_i] = .{ .register = param_int_reg }; + arg_mcv_i += 1; + }, + .memory => { + const param_int_regs = abi.function_arg_regs; + const param_int_reg = param_int_regs[param_int_reg_i]; + + arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; + arg_mcv_i += 1; + }, + else => return self.fail("TODO: C calling convention arg class {}", .{class}), + } else { + arg.* = switch (arg_mcv_i) { + else => return self.fail("ty {} took {} tracking arg indices", .{ ty.fmt(zcu), arg_mcv_i }), + 1 => arg_mcv[0], + 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } }, + }; + continue; + } + + return self.fail("TODO: pass args by stack", .{}); + } }, else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), } - if (ret_ty.zigTypeTag(mod) == .NoReturn) { - result.return_value = .{ .unreach = {} }; - } else if (!ret_ty.hasRuntimeBits(mod)) { - result.return_value = .{ .none = {} }; - } else switch (cc) { - .Naked => unreachable, - .Unspecified, .C => { - const ret_ty_size: u32 = @intCast(ret_ty.abiSize(mod)); - if (ret_ty_size <= 8) { - result.return_value = .{ .register = .a0 }; - } else if (ret_ty_size <= 16) { - return self.fail("TODO support MCValue 2 registers", .{}); - } else { - return self.fail("TODO support return by reference", .{}); - } - }, - else => return self.fail("TODO implement function return values for {}", .{cc}), - } + result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count)); return result; } @@ -2727,11 +5322,37 @@ fn parseRegName(name: []const u8) ?Register { } fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { - const mod = self.bin_file.comp.module.?; - return self.air.typeOf(inst, &mod.intern_pool); + const zcu = self.bin_file.comp.module.?; + return self.air.typeOf(inst, &zcu.intern_pool); } fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { - const mod = self.bin_file.comp.module.?; - return self.air.typeOfIndex(inst, &mod.intern_pool); + const zcu = self.bin_file.comp.module.?; + return self.air.typeOfIndex(inst, &zcu.intern_pool); +} + +fn hasFeature(self: *Self, feature: Target.riscv.Feature) bool { + return Target.riscv.featureSetHas(self.target.cpu.features, feature); +} + +pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Module) u64 { + if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return 0; + const payload_align = payload_ty.abiAlignment(zcu); + const error_align = Type.anyerror.abiAlignment(zcu); + if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { + return 0; + } else { + return payload_align.forward(Type.anyerror.abiSize(zcu)); + } +} + +pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Module) u64 { + if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return 0; + const payload_align = payload_ty.abiAlignment(zcu); + const error_align = Type.anyerror.abiAlignment(zcu); + if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { + return error_align.forward(payload_ty.abiSize(zcu)); + } else { + return 0; + } } diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index f382f6f9eb..ec256fefb3 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -1,25 +1,7 @@ -//! This file contains the functionality for lowering RISCV64 MIR into -//! machine code +//! This file contains the functionality for emitting RISC-V MIR as machine code -const Emit = @This(); -const std = @import("std"); -const math = std.math; -const Mir = @import("Mir.zig"); -const bits = @import("bits.zig"); -const link = @import("../../link.zig"); -const Module = @import("../../Module.zig"); -const ErrorMsg = Module.ErrorMsg; -const assert = std.debug.assert; -const Instruction = bits.Instruction; -const Register = bits.Register; -const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; - -mir: Mir, -bin_file: *link.File, +lower: Lower, debug_output: DebugInfoOutput, -target: *const std.Target, -err_msg: ?*ErrorMsg = null, -src_loc: Module.SrcLoc, code: *std.ArrayList(u8), prev_di_line: u32, @@ -27,195 +9,185 @@ prev_di_column: u32, /// Relative to the beginning of `code`. prev_di_pc: usize, -const InnerError = error{ - OutOfMemory, +code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{}, +relocs: std.ArrayListUnmanaged(Reloc) = .{}, + +pub const Error = Lower.Error || error{ EmitFail, }; -pub fn emitMir( - emit: *Emit, -) InnerError!void { - const mir_tags = emit.mir.instructions.items(.tag); +pub fn emitMir(emit: *Emit) Error!void { + log.debug("mir instruction len: {}", .{emit.lower.mir.instructions.len}); + for (0..emit.lower.mir.instructions.len) |mir_i| { + const mir_index: Mir.Inst.Index = @intCast(mir_i); + try emit.code_offset_mapping.putNoClobber( + emit.lower.allocator, + mir_index, + @intCast(emit.code.items.len), + ); + const lowered = try emit.lower.lowerMir(mir_index); + var lowered_relocs = lowered.relocs; + for (lowered.insts, 0..) |lowered_inst, lowered_index| { + const start_offset: u32 = @intCast(emit.code.items.len); + try lowered_inst.encode(emit.code.writer()); - // Emit machine code - for (mir_tags, 0..) |tag, index| { - const inst = @as(u32, @intCast(index)); - switch (tag) { - .add => try emit.mirRType(inst), - .sub => try emit.mirRType(inst), + while (lowered_relocs.len > 0 and + lowered_relocs[0].lowered_inst_index == lowered_index) : ({ + lowered_relocs = lowered_relocs[1..]; + }) switch (lowered_relocs[0].target) { + .inst => |target| try emit.relocs.append(emit.lower.allocator, .{ + .source = start_offset, + .target = target, + .offset = 0, + .enc = std.meta.activeTag(lowered_inst.encoding.data), + }), + .load_symbol_reloc => |symbol| { + if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; + const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index); + const sym = elf_file.symbol(sym_index); - .addi => try emit.mirIType(inst), - .jalr => try emit.mirIType(inst), - .ld => try emit.mirIType(inst), - .sd => try emit.mirIType(inst), + var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); + var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); - .ebreak => try emit.mirSystem(inst), - .ecall => try emit.mirSystem(inst), - .unimp => try emit.mirSystem(inst), + if (sym.flags.needs_zig_got) { + _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); - .dbg_line => try emit.mirDbgLine(inst), + hi_r_type = Elf.R_ZIG_GOT_HI20; + lo_r_type = Elf.R_ZIG_GOT_LO12; + } - .dbg_prologue_end => try emit.mirDebugPrologueEnd(), - .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), + try atom_ptr.addReloc(elf_file, .{ + .r_offset = start_offset, + .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, + .r_addend = 0, + }); - .mv => try emit.mirRR(inst), + try atom_ptr.addReloc(elf_file, .{ + .r_offset = start_offset + 4, + .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, + .r_addend = 0, + }); + } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{}); + }, + }; + } + std.debug.assert(lowered_relocs.len == 0); - .nop => try emit.mirNop(inst), - .ret => try emit.mirNop(inst), + if (lowered.insts.len == 0) { + const mir_inst = emit.lower.mir.instructions.get(mir_index); + switch (mir_inst.tag) { + else => unreachable, + .pseudo => switch (mir_inst.ops) { + else => unreachable, + .pseudo_dbg_prologue_end => { + switch (emit.debug_output) { + .dwarf => |dw| { + try dw.setPrologueEnd(); + log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ + emit.prev_di_line, emit.prev_di_column, + }); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); + }, + .plan9 => {}, + .none => {}, + } + }, + .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine( + mir_inst.data.pseudo_dbg_line_column.line, + mir_inst.data.pseudo_dbg_line_column.column, + ), + .pseudo_dbg_epilogue_begin => { + switch (emit.debug_output) { + .dwarf => |dw| { + try dw.setEpilogueBegin(); + log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ + emit.prev_di_line, emit.prev_di_column, + }); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); + }, + .plan9 => {}, + .none => {}, + } + }, + .pseudo_dead => {}, + }, + } + } + } + try emit.fixupRelocs(); +} - .lui => try emit.mirUType(inst), +pub fn deinit(emit: *Emit) void { + emit.relocs.deinit(emit.lower.allocator); + emit.code_offset_mapping.deinit(emit.lower.allocator); + emit.* = undefined; +} + +const Reloc = struct { + /// Offset of the instruction. + source: usize, + /// Target of the relocation. + target: Mir.Inst.Index, + /// Offset of the relocation within the instruction. + offset: u32, + /// Encoding of the instruction, used to determine how to modify it. + enc: Encoding.InstEnc, +}; + +fn fixupRelocs(emit: *Emit) Error!void { + for (emit.relocs.items) |reloc| { + log.debug("target inst: {}", .{emit.lower.mir.instructions.get(reloc.target)}); + const target = emit.code_offset_mapping.get(reloc.target) orelse + return emit.fail("relocation target not found!", .{}); + + const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source)); + const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4]; + + log.debug("disp: {x}", .{disp}); + + switch (reloc.enc) { + .J => riscv_util.writeInstJ(code, @bitCast(disp)), + .B => riscv_util.writeInstB(code, @bitCast(disp)), + else => return emit.fail("tried to reloc encoding type {s}", .{@tagName(reloc.enc)}), } } } -pub fn deinit(emit: *Emit) void { - emit.* = undefined; -} - -fn writeInstruction(emit: *Emit, instruction: Instruction) !void { - const endian = emit.target.cpu.arch.endian(); - std.mem.writeInt(u32, try emit.code.addManyAsArray(4), instruction.toU32(), endian); -} - -fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { - @setCold(true); - assert(emit.err_msg == null); - const comp = emit.bin_file.comp; - const gpa = comp.gpa; - emit.err_msg = try ErrorMsg.create(gpa, emit.src_loc, format, args); - return error.EmitFail; -} - -fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { - const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(self.prev_di_line)); - const delta_pc: usize = self.code.items.len - self.prev_di_pc; - switch (self.debug_output) { +fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { + const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); + const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; + log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); + switch (emit.debug_output) { .dwarf => |dw| { + if (column != emit.prev_di_column) try dw.setColumn(column); + if (delta_line == 0) return; // TODO: fix these edge cases. try dw.advancePCAndLine(delta_line, delta_pc); - self.prev_di_line = line; - self.prev_di_column = column; - self.prev_di_pc = self.code.items.len; - }, - .plan9 => |dbg_out| { - if (delta_pc <= 0) return; // only do this when the pc changes - - // increasing the line number - try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line); - // increasing the pc - const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; - if (d_pc_p9 > 0) { - // minus one because if its the last one, we want to leave space to change the line which is one pc quanta - try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); - if (dbg_out.pcop_change_index) |pci| - dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); - } else if (d_pc_p9 == 0) { - // we don't need to do anything, because adding the pc quanta does it for us - } else unreachable; - if (dbg_out.start_line == null) - dbg_out.start_line = self.prev_di_line; - dbg_out.end_line = line; - // only do this if the pc changed - self.prev_di_line = line; - self.prev_di_column = column; - self.prev_di_pc = self.code.items.len; - }, - .none => {}, - } -} - -fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - const r_type = emit.mir.instructions.items(.data)[inst].r_type; - - switch (tag) { - .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)), - .sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)), - else => unreachable, - } -} - -fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - const i_type = emit.mir.instructions.items(.data)[inst].i_type; - - switch (tag) { - .addi => try emit.writeInstruction(Instruction.addi(i_type.rd, i_type.rs1, i_type.imm12)), - .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)), - .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)), - .sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)), - else => unreachable, - } -} - -fn mirSystem(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - - switch (tag) { - .ebreak => try emit.writeInstruction(Instruction.ebreak), - .ecall => try emit.writeInstruction(Instruction.ecall), - .unimp => try emit.writeInstruction(Instruction.unimp), - else => unreachable, - } -} - -fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column; - - switch (tag) { - .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column), - else => unreachable, - } -} - -fn mirDebugPrologueEnd(self: *Emit) !void { - switch (self.debug_output) { - .dwarf => |dw| { - try dw.setPrologueEnd(); - try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); + emit.prev_di_line = line; + emit.prev_di_column = column; + emit.prev_di_pc = emit.code.items.len; }, .plan9 => {}, .none => {}, } } -fn mirDebugEpilogueBegin(self: *Emit) !void { - switch (self.debug_output) { - .dwarf => |dw| { - try dw.setEpilogueBegin(); - try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); - }, - .plan9 => {}, - .none => {}, - } +fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error { + return switch (emit.lower.fail(format, args)) { + error.LowerFail => error.EmitFail, + else => |e| e, + }; } -fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - const rr = emit.mir.instructions.items(.data)[inst].rr; +const link = @import("../../link.zig"); +const log = std.log.scoped(.emit); +const mem = std.mem; +const std = @import("std"); - switch (tag) { - .mv => try emit.writeInstruction(Instruction.addi(rr.rd, rr.rs, 0)), - else => unreachable, - } -} -fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - const u_type = emit.mir.instructions.items(.data)[inst].u_type; - - switch (tag) { - .lui => try emit.writeInstruction(Instruction.lui(u_type.rd, u_type.imm20)), - else => unreachable, - } -} - -fn mirNop(emit: *Emit, inst: Mir.Inst.Index) !void { - const tag = emit.mir.instructions.items(.tag)[inst]; - - switch (tag) { - .nop => try emit.writeInstruction(Instruction.addi(.zero, .zero, 0)), - .ret => try emit.writeInstruction(Instruction.jalr(.zero, 0, .ra)), - else => unreachable, - } -} +const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; +const Emit = @This(); +const Lower = @import("Lower.zig"); +const Mir = @import("Mir.zig"); +const riscv_util = @import("../../link/riscv.zig"); +const Encoding = @import("Encoding.zig"); +const Elf = @import("../../link/Elf.zig"); diff --git a/src/arch/riscv64/Encoding.zig b/src/arch/riscv64/Encoding.zig new file mode 100644 index 0000000000..91f100993b --- /dev/null +++ b/src/arch/riscv64/Encoding.zig @@ -0,0 +1,403 @@ +mnemonic: Mnemonic, +data: Data, + +pub const Mnemonic = enum { + // I Type + ld, + lw, + lwu, + lh, + lhu, + lb, + lbu, + sltiu, + xori, + andi, + slli, + srli, + srai, + + addi, + jalr, + + // U Type + lui, + + // S Type + sd, + sw, + sh, + sb, + + // J Type + jal, + + // B Type + beq, + + // R Type + add, + @"and", + sub, + slt, + mul, + sltu, + xor, + + // System + ecall, + ebreak, + unimp, + + pub fn encoding(mnem: Mnemonic) Enc { + return switch (mnem) { + // zig fmt: off + .add => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000000 }, + .sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 }, + .@"and" => .{ .opcode = 0b0110011, .funct3 = 0b111, .funct7 = 0b0000000 }, + .sub => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0100000 }, + + .ld => .{ .opcode = 0b0000011, .funct3 = 0b011, .funct7 = null }, + .lw => .{ .opcode = 0b0000011, .funct3 = 0b010, .funct7 = null }, + .lwu => .{ .opcode = 0b0000011, .funct3 = 0b110, .funct7 = null }, + .lh => .{ .opcode = 0b0000011, .funct3 = 0b001, .funct7 = null }, + .lhu => .{ .opcode = 0b0000011, .funct3 = 0b101, .funct7 = null }, + .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null }, + .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null }, + + .sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null }, + + .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null }, + .andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null }, + .xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null }, + .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null }, + .slli => .{ .opcode = 0b0010011, .funct3 = 0b001, .funct7 = null }, + .srli => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null }, + .srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 }, + + .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null }, + + .sd => .{ .opcode = 0b0100011, .funct3 = 0b011, .funct7 = null }, + .sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null }, + .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null }, + .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null }, + + .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null }, + + .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null }, + + .slt => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 }, + + .xor => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 }, + + .mul => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000001 }, + + .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null }, + .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null }, + .unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null }, + // zig fmt: on + }; + } +}; + +pub const InstEnc = enum { + R, + I, + S, + B, + U, + J, + + /// extras that have unusual op counts + system, + + pub fn fromMnemonic(mnem: Mnemonic) InstEnc { + return switch (mnem) { + .addi, + .ld, + .lw, + .lwu, + .lh, + .lhu, + .lb, + .lbu, + .jalr, + .sltiu, + .xori, + .andi, + .slli, + .srli, + .srai, + => .I, + + .lui, + => .U, + + .sd, + .sw, + .sh, + .sb, + => .S, + + .jal, + => .J, + + .beq, + => .B, + + .slt, + .sltu, + .mul, + .xor, + .add, + .sub, + .@"and", + => .R, + + .ecall, + .ebreak, + .unimp, + => .system, + }; + } + + pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) { + return switch (enc) { + // zig fmt: off + .R => .{ .reg, .reg, .reg, }, + .I => .{ .reg, .reg, .imm, }, + .S => .{ .reg, .reg, .imm, }, + .B => .{ .reg, .reg, .imm, }, + .U => .{ .reg, .imm, .none, }, + .J => .{ .reg, .imm, .none, }, + .system => .{ .none, .none, .none, }, + // zig fmt: on + }; + } +}; + +pub const Data = union(InstEnc) { + R: packed struct { + opcode: u7, + rd: u5, + funct3: u3, + rs1: u5, + rs2: u5, + funct7: u7, + }, + I: packed struct { + opcode: u7, + rd: u5, + funct3: u3, + rs1: u5, + imm0_11: u12, + }, + S: packed struct { + opcode: u7, + imm0_4: u5, + funct3: u3, + rs1: u5, + rs2: u5, + imm5_11: u7, + }, + B: packed struct { + opcode: u7, + imm11: u1, + imm1_4: u4, + funct3: u3, + rs1: u5, + rs2: u5, + imm5_10: u6, + imm12: u1, + }, + U: packed struct { + opcode: u7, + rd: u5, + imm12_31: u20, + }, + J: packed struct { + opcode: u7, + rd: u5, + imm12_19: u8, + imm11: u1, + imm1_10: u10, + imm20: u1, + }, + system: void, + + pub fn toU32(self: Data) u32 { + return switch (self) { + .R => |v| @as(u32, @bitCast(v)), + .I => |v| @as(u32, @bitCast(v)), + .S => |v| @as(u32, @bitCast(v)), + .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), + .U => |v| @as(u32, @bitCast(v)), + .J => |v| @as(u32, @bitCast(v)), + .system => unreachable, + }; + } + + pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data { + const inst_enc = InstEnc.fromMnemonic(mnem); + + const enc = mnem.encoding(); + + // special mnemonics + switch (mnem) { + .ecall, + .ebreak, + .unimp, + => { + assert(ops.len == 0); + return .{ + .I = .{ + .rd = Register.zero.id(), + .rs1 = Register.zero.id(), + .imm0_11 = switch (mnem) { + .ecall => 0x000, + .ebreak => 0x001, + .unimp => 0, + else => unreachable, + }, + + .opcode = enc.opcode, + .funct3 = enc.funct3.?, + }, + }; + }, + else => {}, + } + + switch (inst_enc) { + .R => { + assert(ops.len == 3); + return .{ + .R = .{ + .rd = ops[0].reg.id(), + .rs1 = ops[1].reg.id(), + .rs2 = ops[2].reg.id(), + + .opcode = enc.opcode, + .funct3 = enc.funct3.?, + .funct7 = enc.funct7.?, + }, + }; + }, + .S => { + assert(ops.len == 3); + const umm = ops[2].imm.asBits(u12); + + return .{ + .S = .{ + .imm0_4 = @truncate(umm), + .rs1 = ops[0].reg.id(), + .rs2 = ops[1].reg.id(), + .imm5_11 = @truncate(umm >> 5), + + .opcode = enc.opcode, + .funct3 = enc.funct3.?, + }, + }; + }, + .I => { + assert(ops.len == 3); + return .{ + .I = .{ + .rd = ops[0].reg.id(), + .rs1 = ops[1].reg.id(), + .imm0_11 = ops[2].imm.asBits(u12) + enc.offset, + + .opcode = enc.opcode, + .funct3 = enc.funct3.?, + }, + }; + }, + .U => { + assert(ops.len == 2); + return .{ + .U = .{ + .rd = ops[0].reg.id(), + .imm12_31 = ops[1].imm.asBits(u20), + + .opcode = enc.opcode, + }, + }; + }, + .J => { + assert(ops.len == 2); + + const umm = ops[1].imm.asBits(u21); + assert(umm % 4 == 0); // misaligned jump target + + return .{ + .J = .{ + .rd = ops[0].reg.id(), + .imm1_10 = @truncate(umm >> 1), + .imm11 = @truncate(umm >> 11), + .imm12_19 = @truncate(umm >> 12), + .imm20 = @truncate(umm >> 20), + + .opcode = enc.opcode, + }, + }; + }, + .B => { + assert(ops.len == 3); + + const umm = ops[2].imm.asBits(u13); + assert(umm % 4 == 0); // misaligned branch target + + return .{ + .B = .{ + .rs1 = ops[0].reg.id(), + .rs2 = ops[1].reg.id(), + .imm1_4 = @truncate(umm >> 1), + .imm5_10 = @truncate(umm >> 5), + .imm11 = @truncate(umm >> 11), + .imm12 = @truncate(umm >> 12), + + .opcode = enc.opcode, + .funct3 = enc.funct3.?, + }, + }; + }, + + else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}), + } + } +}; + +pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding { + if (!verifyOps(mnem, ops)) return null; + + return .{ + .mnemonic = mnem, + .data = try Data.construct(mnem, ops), + }; +} + +const Enc = struct { + opcode: u7, + funct3: ?u3, + funct7: ?u7, + offset: u12 = 0, +}; + +fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool { + const inst_enc = InstEnc.fromMnemonic(mnem); + const list = std.mem.sliceTo(&inst_enc.opsList(), .none); + for (list, ops) |l, o| if (l != std.meta.activeTag(o)) return false; + return true; +} + +const std = @import("std"); +const assert = std.debug.assert; +const log = std.log.scoped(.encoding); + +const Encoding = @This(); +const bits = @import("bits.zig"); +const Register = bits.Register; +const encoder = @import("encoder.zig"); +const Instruction = encoder.Instruction; +const Operand = Instruction.Operand; +const OperandEnum = std.meta.FieldEnum(Operand); diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig new file mode 100644 index 0000000000..4b77f9cdee --- /dev/null +++ b/src/arch/riscv64/Lower.zig @@ -0,0 +1,360 @@ +//! This file contains the functionality for lowering RISC-V MIR to Instructions + +bin_file: *link.File, +output_mode: std.builtin.OutputMode, +link_mode: std.builtin.LinkMode, +pic: bool, +allocator: Allocator, +mir: Mir, +cc: std.builtin.CallingConvention, +err_msg: ?*ErrorMsg = null, +src_loc: Module.SrcLoc, +result_insts_len: u8 = undefined, +result_relocs_len: u8 = undefined, +result_insts: [ + @max( + 1, // non-pseudo instruction + abi.callee_preserved_regs.len, // spill / restore regs, + ) +]Instruction = undefined, +result_relocs: [1]Reloc = undefined, + +pub const Error = error{ + OutOfMemory, + LowerFail, + InvalidInstruction, +}; + +pub const Reloc = struct { + lowered_inst_index: u8, + target: Target, + + const Target = union(enum) { + inst: Mir.Inst.Index, + + /// Relocs the lowered_inst_index and the next one. + load_symbol_reloc: bits.Symbol, + }; +}; + +/// The returned slice is overwritten by the next call to lowerMir. +pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { + insts: []const Instruction, + relocs: []const Reloc, +} { + lower.result_insts = undefined; + lower.result_relocs = undefined; + errdefer lower.result_insts = undefined; + errdefer lower.result_relocs = undefined; + lower.result_insts_len = 0; + lower.result_relocs_len = 0; + defer lower.result_insts_len = undefined; + defer lower.result_relocs_len = undefined; + + const inst = lower.mir.instructions.get(index); + log.debug("lowerMir {}", .{inst}); + switch (inst.tag) { + else => try lower.generic(inst), + .pseudo => switch (inst.ops) { + .pseudo_dbg_line_column, + .pseudo_dbg_epilogue_begin, + .pseudo_dbg_prologue_end, + .pseudo_dead, + => {}, + + .pseudo_load_rm, .pseudo_store_rm => { + const rm = inst.data.rm; + + const frame_loc = rm.m.toFrameLoc(lower.mir); + + switch (inst.ops) { + .pseudo_load_rm => { + const tag: Encoding.Mnemonic = switch (rm.m.mod.rm.size) { + .byte => .lb, + .hword => .lh, + .word => .lw, + .dword => .ld, + }; + + try lower.emit(tag, &.{ + .{ .reg = rm.r }, + .{ .reg = frame_loc.base }, + .{ .imm = Immediate.s(frame_loc.disp) }, + }); + }, + .pseudo_store_rm => { + const tag: Encoding.Mnemonic = switch (rm.m.mod.rm.size) { + .byte => .sb, + .hword => .sh, + .word => .sw, + .dword => .sd, + }; + + try lower.emit(tag, &.{ + .{ .reg = frame_loc.base }, + .{ .reg = rm.r }, + .{ .imm = Immediate.s(frame_loc.disp) }, + }); + }, + else => unreachable, + } + }, + + .pseudo_mv => { + const rr = inst.data.rr; + + try lower.emit(.addi, &.{ + .{ .reg = rr.rd }, + .{ .reg = rr.rs }, + .{ .imm = Immediate.s(0) }, + }); + }, + + .pseudo_ret => { + try lower.emit(.jalr, &.{ + .{ .reg = .zero }, + .{ .reg = .ra }, + .{ .imm = Immediate.s(0) }, + }); + }, + + .pseudo_j => { + try lower.emit(.jal, &.{ + .{ .reg = .zero }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst }) }, + }); + }, + + .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list), + .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list), + + .pseudo_load_symbol => { + const payload = inst.data.payload; + const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data; + + try lower.emit(.lui, &.{ + .{ .reg = @enumFromInt(data.register) }, + .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{ + .atom_index = data.atom_index, + .sym_index = data.sym_index, + } }) }, + }); + + // the above reloc implies this one + try lower.emit(.addi, &.{ + .{ .reg = @enumFromInt(data.register) }, + .{ .reg = @enumFromInt(data.register) }, + .{ .imm = Immediate.s(0) }, + }); + }, + + .pseudo_lea_rm => { + const rm = inst.data.rm; + const frame = rm.m.toFrameLoc(lower.mir); + + try lower.emit(.addi, &.{ + .{ .reg = rm.r }, + .{ .reg = frame.base }, + .{ .imm = Immediate.s(frame.disp) }, + }); + }, + + .pseudo_compare => { + const compare = inst.data.compare; + const op = compare.op; + + const rd = compare.rd; + const rs1 = compare.rs1; + const rs2 = compare.rs2; + + switch (op) { + .eq => { + try lower.emit(.xor, &.{ + .{ .reg = rd }, + .{ .reg = rs1 }, + .{ .reg = rs2 }, + }); + + try lower.emit(.sltiu, &.{ + .{ .reg = rd }, + .{ .reg = rd }, + .{ .imm = Immediate.s(1) }, + }); + }, + .neq => { + try lower.emit(.xor, &.{ + .{ .reg = rd }, + .{ .reg = rs1 }, + .{ .reg = rs2 }, + }); + + try lower.emit(.sltu, &.{ + .{ .reg = rd }, + .{ .reg = .zero }, + .{ .reg = rd }, + }); + }, + .gt => { + try lower.emit(.sltu, &.{ + .{ .reg = rd }, + .{ .reg = rs1 }, + .{ .reg = rs2 }, + }); + }, + .gte => { + try lower.emit(.sltu, &.{ + .{ .reg = rd }, + .{ .reg = rs1 }, + .{ .reg = rs2 }, + }); + + try lower.emit(.xori, &.{ + .{ .reg = rd }, + .{ .reg = rd }, + .{ .imm = Immediate.s(1) }, + }); + }, + .lt => { + try lower.emit(.slt, &.{ + .{ .reg = rd }, + .{ .reg = rs1 }, + .{ .reg = rs2 }, + }); + }, + .lte => { + try lower.emit(.slt, &.{ + .{ .reg = rd }, + .{ .reg = rs2 }, + .{ .reg = rs1 }, + }); + + try lower.emit(.xori, &.{ + .{ .reg = rd }, + .{ .reg = rd }, + .{ .imm = Immediate.s(1) }, + }); + }, + } + }, + + .pseudo_not => { + const rr = inst.data.rr; + + try lower.emit(.xori, &.{ + .{ .reg = rr.rd }, + .{ .reg = rr.rs }, + .{ .imm = Immediate.s(1) }, + }); + }, + + else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}), + }, + } + + return .{ + .insts = lower.result_insts[0..lower.result_insts_len], + .relocs = lower.result_relocs[0..lower.result_relocs_len], + }; +} + +fn generic(lower: *Lower, inst: Mir.Inst) Error!void { + const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse { + return lower.fail("generic inst name '{s}' with op {s} doesn't match with a mnemonic", .{ + @tagName(inst.tag), + @tagName(inst.ops), + }); + }; + try lower.emit(mnemonic, switch (inst.ops) { + .none => &.{}, + .ri => &.{ + .{ .reg = inst.data.u_type.rd }, + .{ .imm = inst.data.u_type.imm20 }, + }, + .rr => &.{ + .{ .reg = inst.data.rr.rd }, + .{ .reg = inst.data.rr.rs }, + }, + .rri => &.{ + .{ .reg = inst.data.i_type.rd }, + .{ .reg = inst.data.i_type.rs1 }, + .{ .imm = inst.data.i_type.imm12 }, + }, + .rr_inst => &.{ + .{ .reg = inst.data.b_type.rs1 }, + .{ .reg = inst.data.b_type.rs2 }, + .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) }, + }, + .rrr => &.{ + .{ .reg = inst.data.r_type.rd }, + .{ .reg = inst.data.r_type.rs1 }, + .{ .reg = inst.data.r_type.rs2 }, + }, + else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}), + }); +} + +fn emit(lower: *Lower, mnemonic: Encoding.Mnemonic, ops: []const Instruction.Operand) !void { + lower.result_insts[lower.result_insts_len] = + try Instruction.new(mnemonic, ops); + lower.result_insts_len += 1; +} + +fn reloc(lower: *Lower, target: Reloc.Target) Immediate { + lower.result_relocs[lower.result_relocs_len] = .{ + .lowered_inst_index = lower.result_insts_len, + .target = target, + }; + lower.result_relocs_len += 1; + return Immediate.s(0); +} + +fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.RegisterList) !void { + var it = reg_list.iterator(.{ .direction = .forward }); + + var reg_i: u31 = 0; + while (it.next()) |i| { + const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame)); + + if (spilling) { + try lower.emit(.sd, &.{ + .{ .reg = frame.base }, + .{ .reg = abi.callee_preserved_regs[i] }, + .{ .imm = Immediate.s(frame.disp + reg_i) }, + }); + } else { + try lower.emit(.ld, &.{ + .{ .reg = abi.callee_preserved_regs[i] }, + .{ .reg = frame.base }, + .{ .imm = Immediate.s(frame.disp + reg_i) }, + }); + } + + reg_i += 8; + } +} + +pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error { + @setCold(true); + assert(lower.err_msg == null); + lower.err_msg = try ErrorMsg.create(lower.allocator, lower.src_loc, format, args); + return error.LowerFail; +} + +const Lower = @This(); + +const abi = @import("abi.zig"); +const assert = std.debug.assert; +const bits = @import("bits.zig"); +const encoder = @import("encoder.zig"); +const link = @import("../../link.zig"); +const Encoding = @import("Encoding.zig"); +const std = @import("std"); +const log = std.log.scoped(.lower); + +const Air = @import("../../Air.zig"); +const Allocator = std.mem.Allocator; +const ErrorMsg = Module.ErrorMsg; +const Mir = @import("Mir.zig"); +const Module = @import("../../Module.zig"); +const Instruction = encoder.Instruction; +const Immediate = bits.Immediate; diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index 9fe29a7ecd..0ce2185197 100644 --- a/src/arch/riscv64/Mir.zig +++ b/src/arch/riscv64/Mir.zig @@ -6,50 +6,111 @@ //! The main purpose of MIR is to postpone the assignment of offsets until Isel, //! so that, for example, the smaller encodings of jump instructions can be used. -const Mir = @This(); -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; - -const bits = @import("bits.zig"); -const Register = bits.Register; - instructions: std.MultiArrayList(Inst).Slice, /// The meaning of this data is determined by `Inst.Tag` value. extra: []const u32, +frame_locs: std.MultiArrayList(FrameLoc).Slice, pub const Inst = struct { tag: Tag, - /// The meaning of this depends on `tag`. data: Data, - - pub const Tag = enum(u16) { - add, - addi, - /// Pseudo-instruction: End of prologue - dbg_prologue_end, - /// Pseudo-instruction: Beginning of epilogue - dbg_epilogue_begin, - /// Pseudo-instruction: Update debug line - dbg_line, - unimp, - ebreak, - ecall, - jalr, - ld, - lui, - mv, - nop, - ret, - sd, - sub, - }; + ops: Ops, /// The position of an MIR instruction within the `Mir` instructions array. pub const Index = u32; + pub const Tag = enum(u16) { + /// Add immediate. Uses i_type payload. + addi, + + /// Add immediate and produce a sign-extended result. + /// + /// Uses i-type payload. + addiw, + + jalr, + lui, + mv, + + @"and", + xor, + + ebreak, + ecall, + unimp, + + /// OR instruction. Uses r_type payload. + @"or", + + /// Addition + add, + /// Subtraction + sub, + /// Multiply, uses r_type. Needs the M extension. + mul, + + /// Absolute Value, uses i_type payload. + abs, + + sltu, + slt, + + /// Immediate Logical Right Shift, uses i_type payload + srli, + /// Immediate Logical Left Shift, uses i_type payload + slli, + /// Immediate Arithmetic Right Shift, uses i_type payload. + srai, + /// Register Logical Left Shift, uses r_type payload + sllw, + /// Register Logical Right Shit, uses r_type payload + srlw, + + /// Jumps, but stores the address of the instruction following the + /// jump in `rd`. + /// + /// Uses j_type payload. + jal, + + /// Immediate AND, uses i_type payload + andi, + + /// Branch if equal, Uses b_type + beq, + /// Branch if not equal, Uses b_type + bne, + + /// Boolean NOT, Uses rr payload + not, + + /// Generates a NO-OP, uses nop payload + nop, + + /// Load double (64 bits), uses i_type payload + ld, + /// Load word (32 bits), uses i_type payload + lw, + /// Load half (16 bits), uses i_type payload + lh, + /// Load byte (8 bits), uses i_type payload + lb, + + /// Store double (64 bits), uses s_type payload + sd, + /// Store word (32 bits), uses s_type payload + sw, + /// Store half (16 bits), uses s_type payload + sh, + /// Store byte (8 bits), uses s_type payload + sb, + + /// A pseudo-instruction. Used for anything that isn't 1:1 with an + /// assembly instruction. + pseudo, + }; + /// All instructions have a 4-byte payload, which is contained within - /// this union. `Tag` determines which union field is active, as well as + /// this union. `Ops` determines which union field is active, as well as /// how to interpret the data within. pub const Data = union { /// No additional data @@ -60,18 +121,69 @@ pub const Inst = struct { /// /// Used by e.g. b inst: Index, - /// A 16-bit immediate value. - /// - /// Used by e.g. svc - imm16: u16, /// Index into `extra`. Meaning of what can be found there is context-dependent. /// /// Used by e.g. load_memory payload: u32, + + r_type: struct { + rd: Register, + rs1: Register, + rs2: Register, + }, + + i_type: struct { + rd: Register, + rs1: Register, + imm12: Immediate, + }, + + s_type: struct { + rs1: Register, + rs2: Register, + imm5: Immediate, + imm7: Immediate, + }, + + b_type: struct { + rs1: Register, + rs2: Register, + inst: Inst.Index, + }, + + u_type: struct { + rd: Register, + imm20: Immediate, + }, + + j_type: struct { + rd: Register, + inst: Inst.Index, + }, + + /// Debug info: line and column + /// + /// Used by e.g. pseudo_dbg_line + pseudo_dbg_line_column: struct { + line: u32, + column: u32, + }, + + // Custom types to be lowered + + /// Register + Memory + rm: struct { + r: Register, + m: Memory, + }, + + reg_list: Mir.RegisterList, + /// A register /// /// Used by e.g. blr reg: Register, + /// Two registers /// /// Used by e.g. mv @@ -79,53 +191,136 @@ pub const Inst = struct { rd: Register, rs: Register, }, - /// I-Type - /// - /// Used by e.g. jalr - i_type: struct { - rd: Register, - rs1: Register, - imm12: i12, - }, - /// R-Type - /// - /// Used by e.g. add - r_type: struct { + + compare: struct { rd: Register, rs1: Register, rs2: Register, - }, - /// U-Type - /// - /// Used by e.g. lui - u_type: struct { - rd: Register, - imm20: i20, - }, - /// Debug info: line and column - /// - /// Used by e.g. dbg_line - dbg_line_column: struct { - line: u32, - column: u32, + op: enum { + eq, + neq, + gt, + gte, + lt, + lte, + }, }, }; + pub const Ops = enum { + /// No data associated with this instruction (only mnemonic is used). + none, + /// Two registers + rr, + /// Three registers + rrr, + + /// Two registers + immediate, uses the i_type payload. + rri, + /// Two registers + Two Immediates + rrii, + + /// Two registers + another instruction. + rr_inst, + + /// Register + Memory + rm, + + /// Register + Immediate + ri, + + /// Another instruction. + inst, + + /// Pseudo-instruction that will generate a backpatched + /// function prologue. + pseudo_prologue, + /// Pseudo-instruction that will generate a backpatched + /// function epilogue + pseudo_epilogue, + + /// Pseudo-instruction: End of prologue + pseudo_dbg_prologue_end, + /// Pseudo-instruction: Beginning of epilogue + pseudo_dbg_epilogue_begin, + /// Pseudo-instruction: Update debug line + pseudo_dbg_line_column, + + /// Pseudo-instruction that loads from memory into a register. + /// + /// Uses `rm` payload. + pseudo_load_rm, + /// Pseudo-instruction that stores from a register into memory + /// + /// Uses `rm` payload. + pseudo_store_rm, + + /// Pseudo-instruction that loads the address of memory into a register. + /// + /// Uses `rm` payload. + pseudo_lea_rm, + + /// Shorthand for returning, aka jumping to ra register. + /// + /// Uses nop payload. + pseudo_ret, + + /// Jumps. Uses `inst` payload. + pseudo_j, + + /// Dead inst, ignored by the emitter. + pseudo_dead, + + /// Loads the address of a value that hasn't yet been allocated in memory. + /// + /// uses the Mir.LoadSymbolPayload payload. + pseudo_load_symbol, + + /// Moves the value of rs1 to rd. + /// + /// uses the `rr` payload. + pseudo_mv, + + pseudo_restore_regs, + pseudo_spill_regs, + + pseudo_compare, + pseudo_not, + }; + // Make sure we don't accidentally make instructions bigger than expected. - // Note that in safety builds, Zig is allowed to insert a secret field for safety checks. + // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. // comptime { - // if (!std.debug.runtime_safety) { + // if (builtin.mode != .Debug) { // assert(@sizeOf(Inst) == 8); // } // } + + pub fn format( + inst: Inst, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + assert(fmt.len == 0); + _ = options; + + try writer.print("Tag: {s}, Ops: {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }); + } }; pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { mir.instructions.deinit(gpa); + mir.frame_locs.deinit(gpa); gpa.free(mir.extra); mir.* = undefined; } +pub const FrameLoc = struct { + base: Register, + disp: i32, +}; + /// Returns the requested data, as well as the new index which is at the start of the /// trailers for the object. pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { @@ -145,3 +340,59 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end .end = i, }; } + +pub const LoadSymbolPayload = struct { + register: u32, + atom_index: u32, + sym_index: u32, +}; + +/// Used in conjunction with payload to transfer a list of used registers in a compact manner. +pub const RegisterList = struct { + bitset: BitSet = BitSet.initEmpty(), + + const BitSet = IntegerBitSet(32); + const Self = @This(); + + fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt { + for (registers, 0..) |cpreg, i| { + if (reg.id() == cpreg.id()) return @intCast(i); + } + unreachable; // register not in input register list! + } + + pub fn push(self: *Self, registers: []const Register, reg: Register) void { + const index = getIndexForReg(registers, reg); + self.bitset.set(index); + } + + pub fn isSet(self: Self, registers: []const Register, reg: Register) bool { + const index = getIndexForReg(registers, reg); + return self.bitset.isSet(index); + } + + pub fn iterator(self: Self, comptime options: std.bit_set.IteratorOptions) BitSet.Iterator(options) { + return self.bitset.iterator(options); + } + + pub fn count(self: Self) i32 { + return @intCast(self.bitset.count()); + } + + pub fn size(self: Self) i32 { + return @intCast(self.bitset.count() * 8); + } +}; + +const Mir = @This(); +const std = @import("std"); +const builtin = @import("builtin"); +const assert = std.debug.assert; + +const bits = @import("bits.zig"); +const Register = bits.Register; +const Immediate = bits.Immediate; +const Memory = bits.Memory; +const FrameIndex = bits.FrameIndex; +const FrameAddr = @import("CodeGen.zig").FrameAddr; +const IntegerBitSet = std.bit_set.IntegerBitSet; diff --git a/src/arch/riscv64/abi.zig b/src/arch/riscv64/abi.zig index be3ac590a2..35f5659685 100644 --- a/src/arch/riscv64/abi.zig +++ b/src/arch/riscv64/abi.zig @@ -3,9 +3,11 @@ const bits = @import("bits.zig"); const Register = bits.Register; const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; const Type = @import("../../type.zig").Type; +const InternPool = @import("../../InternPool.zig"); const Module = @import("../../Module.zig"); +const assert = std.debug.assert; -pub const Class = enum { memory, byval, integer, double_integer, fields }; +pub const Class = enum { memory, byval, integer, double_integer, fields, none }; pub fn classifyType(ty: Type, mod: *Module) Class { const target = mod.getTarget(); @@ -91,11 +93,161 @@ pub fn classifyType(ty: Type, mod: *Module) Class { } } +/// There are a maximum of 8 possible return slots. Returned values are in +/// the beginning of the array; unused slots are filled with .none. +pub fn classifySystem(ty: Type, zcu: *Module) [8]Class { + var result = [1]Class{.none} ** 8; + const memory_class = [_]Class{ + .memory, .none, .none, .none, + .none, .none, .none, .none, + }; + switch (ty.zigTypeTag(zcu)) { + .Bool, .Void, .NoReturn => { + result[0] = .integer; + return result; + }, + .Pointer => switch (ty.ptrSize(zcu)) { + .Slice => { + result[0] = .integer; + result[1] = .integer; + return result; + }, + else => { + result[0] = .integer; + return result; + }, + }, + .Optional => { + if (ty.isPtrLikeOptional(zcu)) { + result[0] = .integer; + return result; + } + result[0] = .integer; + result[1] = .integer; + return result; + }, + .Int, .Enum, .ErrorSet => { + const int_bits = ty.intInfo(zcu).bits; + if (int_bits <= 64) { + result[0] = .integer; + return result; + } + if (int_bits <= 128) { + result[0] = .integer; + result[1] = .integer; + return result; + } + unreachable; // support > 128 bit int arguments + }, + .ErrorUnion => { + const payload_ty = ty.errorUnionPayload(zcu); + const payload_bits = payload_ty.bitSize(zcu); + + // the error union itself + result[0] = .integer; + + // anyerror!void can fit into one register + if (payload_bits == 0) return result; + + if (payload_bits <= 64) { + result[1] = .integer; + return result; + } + + std.debug.panic("TODO: classifySystem ErrorUnion > 64 bit payload", .{}); + }, + .Struct => { + const layout = ty.containerLayout(zcu); + const ty_size = ty.abiSize(zcu); + + if (layout == .@"packed") { + assert(ty_size <= 16); + result[0] = .integer; + if (ty_size > 8) result[1] = .integer; + return result; + } + + return memory_class; + }, + else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}), + } +} + +fn classifyStruct( + result: *[8]Class, + byte_offset: *u64, + loaded_struct: InternPool.LoadedStructType, + zcu: *Module, +) void { + const ip = &zcu.intern_pool; + var field_it = loaded_struct.iterateRuntimeOrder(ip); + + while (field_it.next()) |field_index| { + const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); + const field_align = loaded_struct.fieldAlign(ip, field_index); + byte_offset.* = std.mem.alignForward( + u64, + byte_offset.*, + field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?, + ); + if (zcu.typeToStruct(field_ty)) |field_loaded_struct| { + if (field_loaded_struct.layout != .@"packed") { + classifyStruct(result, byte_offset, field_loaded_struct, zcu); + continue; + } + } + const field_class = std.mem.sliceTo(&classifySystem(field_ty, zcu), .none); + const field_size = field_ty.abiSize(zcu); + + combine: { + const result_class = &result[@intCast(byte_offset.* / 8)]; + if (result_class.* == field_class[0]) { + break :combine; + } + + if (result_class.* == .none) { + result_class.* = field_class[0]; + break :combine; + } + assert(field_class[0] != .none); + + // "If one of the classes is MEMORY, the result is the MEMORY class." + if (result_class.* == .memory or field_class[0] == .memory) { + result_class.* = .memory; + break :combine; + } + + // "If one of the classes is INTEGER, the result is the INTEGER." + if (result_class.* == .integer or field_class[0] == .integer) { + result_class.* = .integer; + break :combine; + } + + result_class.* = .integer; + } + @memcpy(result[@intCast(byte_offset.* / 8 + 1)..][0 .. field_class.len - 1], field_class[1..]); + byte_offset.* += field_size; + } +} + pub const callee_preserved_regs = [_]Register{ - .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11, + // .s0 is ommited to be used as a frame pointer + .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11, }; -const allocatable_registers = callee_preserved_regs; +pub const function_arg_regs = [_]Register{ + .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7, +}; + +pub const function_ret_regs = [_]Register{ + .a0, .a1, +}; + +pub const temporary_regs = [_]Register{ + .t0, .t1, .t2, .t3, .t4, .t5, .t6, +}; + +const allocatable_registers = callee_preserved_regs ++ function_arg_regs ++ temporary_regs; pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); // Register classes @@ -109,4 +261,31 @@ pub const RegisterClass = struct { }, true); break :blk set; }; + + pub const fa: RegisterBitSet = blk: { + var set = RegisterBitSet.initEmpty(); + set.setRangeValue(.{ + .start = callee_preserved_regs.len, + .end = callee_preserved_regs.len + function_arg_regs.len, + }, true); + break :blk set; + }; + + pub const fr: RegisterBitSet = blk: { + var set = RegisterBitSet.initEmpty(); + set.setRangeValue(.{ + .start = callee_preserved_regs.len, + .end = callee_preserved_regs.len + function_ret_regs.len, + }, true); + break :blk set; + }; + + pub const tp: RegisterBitSet = blk: { + var set = RegisterBitSet.initEmpty(); + set.setRangeValue(.{ + .start = callee_preserved_regs.len + function_arg_regs.len, + .end = callee_preserved_regs.len + function_arg_regs.len + temporary_regs.len, + }, true); + break :blk set; + }; }; diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index 2239bd49f8..eef0828cdb 100644 --- a/src/arch/riscv64/bits.zig +++ b/src/arch/riscv64/bits.zig @@ -2,385 +2,149 @@ const std = @import("std"); const DW = std.dwarf; const assert = std.debug.assert; const testing = std.testing; +const Encoding = @import("Encoding.zig"); +const Mir = @import("Mir.zig"); -// TODO: this is only tagged to facilitate the monstrosity. -// Once packed structs work make it packed. -pub const Instruction = union(enum) { - R: packed struct { - opcode: u7, - rd: u5, - funct3: u3, - rs1: u5, - rs2: u5, - funct7: u7, - }, - I: packed struct { - opcode: u7, - rd: u5, - funct3: u3, - rs1: u5, - imm0_11: u12, - }, - S: packed struct { - opcode: u7, - imm0_4: u5, - funct3: u3, - rs1: u5, - rs2: u5, - imm5_11: u7, - }, - B: packed struct { - opcode: u7, - imm11: u1, - imm1_4: u4, - funct3: u3, - rs1: u5, - rs2: u5, - imm5_10: u6, - imm12: u1, - }, - U: packed struct { - opcode: u7, - rd: u5, - imm12_31: u20, - }, - J: packed struct { - opcode: u7, - rd: u5, - imm12_19: u8, - imm11: u1, - imm1_10: u10, - imm20: u1, - }, +pub const Memory = struct { + base: Base, + mod: Mod, - // TODO: once packed structs work we can remove this monstrosity. - pub fn toU32(self: Instruction) u32 { - return switch (self) { - .R => |v| @as(u32, @bitCast(v)), - .I => |v| @as(u32, @bitCast(v)), - .S => |v| @as(u32, @bitCast(v)), - .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), - .U => |v| @as(u32, @bitCast(v)), - .J => |v| @as(u32, @bitCast(v)), + pub const Base = union(enum) { + reg: Register, + frame: FrameIndex, + reloc: Symbol, + }; + + pub const Mod = union(enum(u1)) { + rm: struct { + size: Size, + disp: i32 = 0, + }, + off: i32, + }; + + pub const Size = enum(u4) { + /// Byte, 1 byte + byte, + /// Half word, 2 bytes + hword, + /// Word, 4 bytes + word, + /// Double word, 8 Bytes + dword, + + pub fn fromByteSize(size: u64) Size { + return switch (size) { + 1 => .byte, + 2 => .hword, + 4 => .word, + 8 => .dword, + else => unreachable, + }; + } + + pub fn fromBitSize(bit_size: u64) Size { + return switch (bit_size) { + 8 => .byte, + 16 => .hword, + 32 => .word, + 64 => .dword, + else => unreachable, + }; + } + + pub fn bitSize(s: Size) u64 { + return switch (s) { + .byte => 8, + .hword => 16, + .word => 32, + .dword => 64, + }; + } + }; + + /// Asserts `mem` can be represented as a `FrameLoc`. + pub fn toFrameLoc(mem: Memory, mir: Mir) Mir.FrameLoc { + const offset: i32 = switch (mem.mod) { + .off => |off| off, + .rm => |rm| rm.disp, }; + + switch (mem.base) { + .reg => |reg| { + return .{ + .base = reg, + .disp = offset, + }; + }, + .frame => |index| { + const base_loc = mir.frame_locs.get(@intFromEnum(index)); + return .{ + .base = base_loc.base, + .disp = base_loc.disp + offset, + }; + }, + .reloc => unreachable, + } + } +}; + +pub const Immediate = union(enum) { + signed: i32, + unsigned: u32, + + pub fn u(x: u64) Immediate { + return .{ .unsigned = x }; } - fn rType(op: u7, fn3: u3, fn7: u7, rd: Register, r1: Register, r2: Register) Instruction { - return Instruction{ - .R = .{ - .opcode = op, - .funct3 = fn3, - .funct7 = fn7, - .rd = rd.id(), - .rs1 = r1.id(), - .rs2 = r2.id(), + pub fn s(x: i32) Immediate { + return .{ .signed = x }; + } + + pub fn asSigned(imm: Immediate, bit_size: u64) i64 { + return switch (imm) { + .signed => |x| switch (bit_size) { + 1, 8 => @as(i8, @intCast(x)), + 16 => @as(i16, @intCast(x)), + 32, 64 => x, + else => unreachable, + }, + .unsigned => |x| switch (bit_size) { + 1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))), + 16 => @as(i16, @bitCast(@as(u16, @intCast(x)))), + 32 => @as(i32, @bitCast(@as(u32, @intCast(x)))), + 64 => @bitCast(x), + else => unreachable, }, }; } - // RISC-V is all signed all the time -- convert immediates to unsigned for processing - fn iType(op: u7, fn3: u3, rd: Register, r1: Register, imm: i12) Instruction { - const umm = @as(u12, @bitCast(imm)); - - return Instruction{ - .I = .{ - .opcode = op, - .funct3 = fn3, - .rd = rd.id(), - .rs1 = r1.id(), - .imm0_11 = umm, + pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 { + return switch (imm) { + .signed => |x| switch (bit_size) { + 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))), + 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))), + 32, 64 => @as(u32, @bitCast(x)), + else => unreachable, + }, + .unsigned => |x| switch (bit_size) { + 1, 8 => @as(u8, @intCast(x)), + 16 => @as(u16, @intCast(x)), + 32 => @as(u32, @intCast(x)), + 64 => x, + else => unreachable, }, }; } - fn sType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i12) Instruction { - const umm = @as(u12, @bitCast(imm)); - - return Instruction{ - .S = .{ - .opcode = op, - .funct3 = fn3, - .rs1 = r1.id(), - .rs2 = r2.id(), - .imm0_4 = @as(u5, @truncate(umm)), - .imm5_11 = @as(u7, @truncate(umm >> 5)), - }, + pub fn asBits(imm: Immediate, comptime T: type) T { + const int_info = @typeInfo(T).Int; + if (int_info.signedness != .unsigned) @compileError("Immediate.asBits needs unsigned T"); + return switch (imm) { + .signed => |x| @bitCast(@as(std.meta.Int(.signed, int_info.bits), @intCast(x))), + .unsigned => |x| @intCast(x), }; } - - // Use significance value rather than bit value, same for J-type - // -- less burden on callsite, bonus semantic checking - fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction { - const umm = @as(u13, @bitCast(imm)); - assert(umm % 2 == 0); // misaligned branch target - - return Instruction{ - .B = .{ - .opcode = op, - .funct3 = fn3, - .rs1 = r1.id(), - .rs2 = r2.id(), - .imm1_4 = @as(u4, @truncate(umm >> 1)), - .imm5_10 = @as(u6, @truncate(umm >> 5)), - .imm11 = @as(u1, @truncate(umm >> 11)), - .imm12 = @as(u1, @truncate(umm >> 12)), - }, - }; - } - - // We have to extract the 20 bits anyway -- let's not make it more painful - fn uType(op: u7, rd: Register, imm: i20) Instruction { - const umm = @as(u20, @bitCast(imm)); - - return Instruction{ - .U = .{ - .opcode = op, - .rd = rd.id(), - .imm12_31 = umm, - }, - }; - } - - fn jType(op: u7, rd: Register, imm: i21) Instruction { - const umm = @as(u21, @bitCast(imm)); - assert(umm % 2 == 0); // misaligned jump target - - return Instruction{ - .J = .{ - .opcode = op, - .rd = rd.id(), - .imm1_10 = @as(u10, @truncate(umm >> 1)), - .imm11 = @as(u1, @truncate(umm >> 11)), - .imm12_19 = @as(u8, @truncate(umm >> 12)), - .imm20 = @as(u1, @truncate(umm >> 20)), - }, - }; - } - - // The meat and potatoes. Arguments are in the order in which they would appear in assembly code. - - // Arithmetic/Logical, Register-Register - - pub fn add(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b000, 0b0000000, rd, r1, r2); - } - - pub fn sub(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b000, 0b0100000, rd, r1, r2); - } - - pub fn @"and"(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b111, 0b0000000, rd, r1, r2); - } - - pub fn @"or"(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b110, 0b0000000, rd, r1, r2); - } - - pub fn xor(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b100, 0b0000000, rd, r1, r2); - } - - pub fn sll(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b001, 0b0000000, rd, r1, r2); - } - - pub fn srl(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b101, 0b0000000, rd, r1, r2); - } - - pub fn sra(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b101, 0b0100000, rd, r1, r2); - } - - pub fn slt(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b010, 0b0000000, rd, r1, r2); - } - - pub fn sltu(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0110011, 0b011, 0b0000000, rd, r1, r2); - } - - // Arithmetic/Logical, Register-Register (32-bit) - - pub fn addw(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0111011, 0b000, rd, r1, r2); - } - - pub fn subw(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0111011, 0b000, 0b0100000, rd, r1, r2); - } - - pub fn sllw(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0111011, 0b001, 0b0000000, rd, r1, r2); - } - - pub fn srlw(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0111011, 0b101, 0b0000000, rd, r1, r2); - } - - pub fn sraw(rd: Register, r1: Register, r2: Register) Instruction { - return rType(0b0111011, 0b101, 0b0100000, rd, r1, r2); - } - - // Arithmetic/Logical, Register-Immediate - - pub fn addi(rd: Register, r1: Register, imm: i12) Instruction { - return iType(0b0010011, 0b000, rd, r1, imm); - } - - pub fn andi(rd: Register, r1: Register, imm: i12) Instruction { - return iType(0b0010011, 0b111, rd, r1, imm); - } - - pub fn ori(rd: Register, r1: Register, imm: i12) Instruction { - return iType(0b0010011, 0b110, rd, r1, imm); - } - - pub fn xori(rd: Register, r1: Register, imm: i12) Instruction { - return iType(0b0010011, 0b100, rd, r1, imm); - } - - pub fn slli(rd: Register, r1: Register, shamt: u6) Instruction { - return iType(0b0010011, 0b001, rd, r1, shamt); - } - - pub fn srli(rd: Register, r1: Register, shamt: u6) Instruction { - return iType(0b0010011, 0b101, rd, r1, shamt); - } - - pub fn srai(rd: Register, r1: Register, shamt: u6) Instruction { - return iType(0b0010011, 0b101, rd, r1, (1 << 10) + shamt); - } - - pub fn slti(rd: Register, r1: Register, imm: i12) Instruction { - return iType(0b0010011, 0b010, rd, r1, imm); - } - - pub fn sltiu(rd: Register, r1: Register, imm: u12) Instruction { - return iType(0b0010011, 0b011, rd, r1, @as(i12, @bitCast(imm))); - } - - // Arithmetic/Logical, Register-Immediate (32-bit) - - pub fn addiw(rd: Register, r1: Register, imm: i12) Instruction { - return iType(0b0011011, 0b000, rd, r1, imm); - } - - pub fn slliw(rd: Register, r1: Register, shamt: u5) Instruction { - return iType(0b0011011, 0b001, rd, r1, shamt); - } - - pub fn srliw(rd: Register, r1: Register, shamt: u5) Instruction { - return iType(0b0011011, 0b101, rd, r1, shamt); - } - - pub fn sraiw(rd: Register, r1: Register, shamt: u5) Instruction { - return iType(0b0011011, 0b101, rd, r1, (1 << 10) + shamt); - } - - // Upper Immediate - - pub fn lui(rd: Register, imm: i20) Instruction { - return uType(0b0110111, rd, imm); - } - - pub fn auipc(rd: Register, imm: i20) Instruction { - return uType(0b0010111, rd, imm); - } - - // Load - - pub fn ld(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b011, rd, base, offset); - } - - pub fn lw(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b010, rd, base, offset); - } - - pub fn lwu(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b110, rd, base, offset); - } - - pub fn lh(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b001, rd, base, offset); - } - - pub fn lhu(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b101, rd, base, offset); - } - - pub fn lb(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b000, rd, base, offset); - } - - pub fn lbu(rd: Register, offset: i12, base: Register) Instruction { - return iType(0b0000011, 0b100, rd, base, offset); - } - - // Store - - pub fn sd(rs: Register, offset: i12, base: Register) Instruction { - return sType(0b0100011, 0b011, base, rs, offset); - } - - pub fn sw(rs: Register, offset: i12, base: Register) Instruction { - return sType(0b0100011, 0b010, base, rs, offset); - } - - pub fn sh(rs: Register, offset: i12, base: Register) Instruction { - return sType(0b0100011, 0b001, base, rs, offset); - } - - pub fn sb(rs: Register, offset: i12, base: Register) Instruction { - return sType(0b0100011, 0b000, base, rs, offset); - } - - // Fence - // TODO: implement fence - - // Branch - - pub fn beq(r1: Register, r2: Register, offset: i13) Instruction { - return bType(0b1100011, 0b000, r1, r2, offset); - } - - pub fn bne(r1: Register, r2: Register, offset: i13) Instruction { - return bType(0b1100011, 0b001, r1, r2, offset); - } - - pub fn blt(r1: Register, r2: Register, offset: i13) Instruction { - return bType(0b1100011, 0b100, r1, r2, offset); - } - - pub fn bge(r1: Register, r2: Register, offset: i13) Instruction { - return bType(0b1100011, 0b101, r1, r2, offset); - } - - pub fn bltu(r1: Register, r2: Register, offset: i13) Instruction { - return bType(0b1100011, 0b110, r1, r2, offset); - } - - pub fn bgeu(r1: Register, r2: Register, offset: i13) Instruction { - return bType(0b1100011, 0b111, r1, r2, offset); - } - - // Jump - - pub fn jal(link: Register, offset: i21) Instruction { - return jType(0b1101111, link, offset); - } - - pub fn jalr(link: Register, offset: i12, base: Register) Instruction { - return iType(0b1100111, 0b000, link, base, offset); - } - - // System - - pub const ecall = iType(0b1110011, 0b000, .zero, .zero, 0x000); - pub const ebreak = iType(0b1110011, 0b000, .zero, .zero, 0x001); - pub const unimp = iType(0, 0, .zero, .zero, 0); }; pub const Register = enum(u6) { @@ -404,50 +168,63 @@ pub const Register = enum(u6) { t3, t4, t5, t6, // caller saved // zig fmt: on - /// Returns the unique 4-bit ID of this register which is used in + /// Returns the unique 5-bit ID of this register which is used in /// the machine code pub fn id(self: Register) u5 { return @as(u5, @truncate(@intFromEnum(self))); } pub fn dwarfLocOp(reg: Register) u8 { - return @as(u8, reg.id()) + DW.OP.reg0; + return @as(u8, reg.id()); } }; -// zig fmt: on +pub const FrameIndex = enum(u32) { + /// This index refers to the return address. + ret_addr, + /// This index refers to the frame pointer. + base_ptr, + /// This index refers to the entire stack frame. + stack_frame, + /// This index referes to where in the stack frame the args are spilled to. + args_frame, + /// This index referes to a frame dedicated to setting up args for function called + /// in this function. Useful for aligning args separately. + call_frame, + /// This index referes to the frame where callee saved registers are spilled and restore + /// from. + spill_frame, + /// Other indices are used for local variable stack slots + _, -test "serialize instructions" { - const Testcase = struct { - inst: Instruction, - expected: u32, - }; + pub const named_count = @typeInfo(FrameIndex).Enum.fields.len; - const testcases = [_]Testcase{ - .{ // add t6, zero, zero - .inst = Instruction.add(.t6, .zero, .zero), - .expected = 0b0000000_00000_00000_000_11111_0110011, - }, - .{ // sd s0, 0x7f(s0) - .inst = Instruction.sd(.s0, 0x7f, .s0), - .expected = 0b0000011_01000_01000_011_11111_0100011, - }, - .{ // bne s0, s1, 0x42 - .inst = Instruction.bne(.s0, .s1, 0x42), - .expected = 0b0_000010_01001_01000_001_0001_0_1100011, - }, - .{ // j 0x1a - .inst = Instruction.jal(.zero, 0x1a), - .expected = 0b0_0000001101_0_00000000_00000_1101111, - }, - .{ // ebreak - .inst = Instruction.ebreak, - .expected = 0b000000000001_00000_000_00000_1110011, - }, - }; - - for (testcases) |case| { - const actual = case.inst.toU32(); - try testing.expectEqual(case.expected, actual); + pub fn isNamed(fi: FrameIndex) bool { + return @intFromEnum(fi) < named_count; } -} + + pub fn format( + fi: FrameIndex, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) @TypeOf(writer).Error!void { + try writer.writeAll("FrameIndex"); + if (fi.isNamed()) { + try writer.writeByte('.'); + try writer.writeAll(@tagName(fi)); + } else { + try writer.writeByte('('); + try std.fmt.formatType(@intFromEnum(fi), fmt, options, writer, 0); + try writer.writeByte(')'); + } + } +}; + +/// A linker symbol not yet allocated in VM. +pub const Symbol = struct { + /// Index of the containing atom. + atom_index: u32, + /// Index into the linker's symbol table. + sym_index: u32, +}; diff --git a/src/arch/riscv64/encoder.zig b/src/arch/riscv64/encoder.zig new file mode 100644 index 0000000000..ddd4f5f437 --- /dev/null +++ b/src/arch/riscv64/encoder.zig @@ -0,0 +1,49 @@ +pub const Instruction = struct { + encoding: Encoding, + ops: [3]Operand = .{.none} ** 3, + + pub const Operand = union(enum) { + none, + reg: Register, + mem: Memory, + imm: Immediate, + }; + + pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction { + const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse { + std.log.err("no encoding found for: {s} {s} {s} {s} {s}", .{ + @tagName(mnemonic), + @tagName(if (ops.len > 0) ops[0] else .none), + @tagName(if (ops.len > 1) ops[1] else .none), + @tagName(if (ops.len > 2) ops[2] else .none), + @tagName(if (ops.len > 3) ops[3] else .none), + }); + return error.InvalidInstruction; + }; + + var result_ops: [3]Operand = .{.none} ** 3; + @memcpy(result_ops[0..ops.len], ops); + + return .{ + .encoding = encoding, + .ops = result_ops, + }; + } + + pub fn encode(inst: Instruction, writer: anytype) !void { + try writer.writeInt(u32, inst.encoding.data.toU32(), .little); + } +}; + +const std = @import("std"); + +const Lower = @import("Lower.zig"); +const Mir = @import("Mir.zig"); +const bits = @import("bits.zig"); +const Encoding = @import("Encoding.zig"); + +const Register = bits.Register; +const Memory = bits.Memory; +const Immediate = bits.Immediate; + +const log = std.log.scoped(.encode); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 04a5af8bb0..5b42a701ff 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -11132,6 +11132,7 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu } return o.builder.structType(.normal, types[0..types_len]); }, + .none => unreachable, } }, // TODO investigate C ABI for other architectures @@ -11389,6 +11390,7 @@ const ParamTypeIterator = struct { it.llvm_index += it.types_len - 1; return .multiple_llvm_types; }, + .none => unreachable, } }, // TODO investigate C ABI for other architectures diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a1e23945ee..8a3192f93e 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -6409,6 +6409,8 @@ const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection); // TODO: add comptime check we don't clobber any reloc for any ISA pub const R_ZIG_GOT32: u32 = 0xff00; pub const R_ZIG_GOTPCREL: u32 = 0xff01; +pub const R_ZIG_GOT_HI20: u32 = 0xff02; +pub const R_ZIG_GOT_LO12: u32 = 0xff03; fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { return switch (cpu_arch) { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 90056cc4c5..239186ffaa 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -2025,7 +2025,15 @@ const riscv = struct { .SUB32, => {}, - else => try atom.reportUnhandledRelocError(rel, elf_file), + else => |x| switch (@intFromEnum(x)) { + Elf.R_ZIG_GOT_HI20, + Elf.R_ZIG_GOT_LO12, + => { + assert(symbol.flags.has_zig_got); + }, + + else => try atom.reportUnhandledRelocError(rel, elf_file), + }, } } @@ -2046,7 +2054,6 @@ const riscv = struct { const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; _ = TP; _ = DTP; - _ = ZIG_GOT; switch (r_type) { .NONE => unreachable, @@ -2136,7 +2143,22 @@ const riscv = struct { } }, - else => try atom.reportUnhandledRelocError(rel, elf_file), + else => |x| switch (@intFromEnum(x)) { + // Zig custom relocations + Elf.R_ZIG_GOT_HI20 => { + assert(target.flags.has_zig_got); + const disp: u32 = @bitCast(math.cast(i32, G + ZIG_GOT + A) orelse return error.Overflow); + riscv_util.writeInstU(code[r_offset..][0..4], disp); + }, + + Elf.R_ZIG_GOT_LO12 => { + assert(target.flags.has_zig_got); + const value: u32 = @bitCast(math.cast(i32, G + ZIG_GOT + A) orelse return error.Overflow); + riscv_util.writeInstI(code[r_offset..][0..4], value); + }, + + else => try atom.reportUnhandledRelocError(rel, elf_file), + }, } } diff --git a/src/link/riscv.zig b/src/link/riscv.zig index 85e4098200..e78cb84cdf 100644 --- a/src/link/riscv.zig +++ b/src/link/riscv.zig @@ -25,38 +25,66 @@ pub fn writeAddend( } pub fn writeInstU(code: *[4]u8, value: u32) void { - var inst = Instruction{ + var data = Encoding.Data{ .U = mem.bytesToValue(std.meta.TagPayload( - Instruction, - Instruction.U, + Encoding.Data, + Encoding.Data.U, ), code), }; const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800); - inst.U.imm12_31 = bitSlice(compensated, 31, 12); - mem.writeInt(u32, code, inst.toU32(), .little); + data.U.imm12_31 = bitSlice(compensated, 31, 12); + mem.writeInt(u32, code, data.toU32(), .little); } pub fn writeInstI(code: *[4]u8, value: u32) void { - var inst = Instruction{ + var data = Encoding.Data{ .I = mem.bytesToValue(std.meta.TagPayload( - Instruction, - Instruction.I, + Encoding.Data, + Encoding.Data.I, ), code), }; - inst.I.imm0_11 = bitSlice(value, 11, 0); - mem.writeInt(u32, code, inst.toU32(), .little); + data.I.imm0_11 = bitSlice(value, 11, 0); + mem.writeInt(u32, code, data.toU32(), .little); } pub fn writeInstS(code: *[4]u8, value: u32) void { - var inst = Instruction{ + var data = Encoding.Data{ .S = mem.bytesToValue(std.meta.TagPayload( - Instruction, - Instruction.S, + Encoding.Data, + Encoding.Data.S, ), code), }; - inst.S.imm0_4 = bitSlice(value, 4, 0); - inst.S.imm5_11 = bitSlice(value, 11, 5); - mem.writeInt(u32, code, inst.toU32(), .little); + data.S.imm0_4 = bitSlice(value, 4, 0); + data.S.imm5_11 = bitSlice(value, 11, 5); + mem.writeInt(u32, code, data.toU32(), .little); +} + +pub fn writeInstJ(code: *[4]u8, value: u32) void { + var data = Encoding.Data{ + .J = mem.bytesToValue(std.meta.TagPayload( + Encoding.Data, + Encoding.Data.J, + ), code), + }; + data.J.imm1_10 = bitSlice(value, 10, 1); + data.J.imm11 = bitSlice(value, 11, 11); + data.J.imm12_19 = bitSlice(value, 19, 12); + data.J.imm20 = bitSlice(value, 20, 20); + mem.writeInt(u32, code, data.toU32(), .little); +} + +pub fn writeInstB(code: *[4]u8, value: u32) void { + var data = Encoding.Data{ + .B = mem.bytesToValue(std.meta.TagPayload( + Encoding.Data, + Encoding.Data.B, + ), code), + }; + data.B.imm1_4 = bitSlice(value, 4, 1); + data.B.imm5_10 = bitSlice(value, 10, 5); + data.B.imm11 = bitSlice(value, 11, 11); + data.B.imm12 = bitSlice(value, 12, 12); + mem.writeInt(u32, code, data.toU32(), .little); } fn bitSlice( @@ -67,8 +95,9 @@ fn bitSlice( return @truncate((value >> low) & (1 << (high - low + 1)) - 1); } -const bits = @import("../arch/riscv64/bits.zig"); +const encoder = @import("../arch/riscv64/encoder.zig"); +const Encoding = @import("../arch/riscv64/Encoding.zig"); const mem = std.mem; const std = @import("std"); -pub const Instruction = bits.Instruction; +pub const Instruction = encoder.Instruction; diff --git a/src/register_manager.zig b/src/register_manager.zig index d1d773ed10..bd596f5658 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -102,7 +102,7 @@ pub fn RegisterManager( } const OptionalIndex = std.math.IntFittingRange(0, set.len); - comptime var map = [1]OptionalIndex{set.len} ** (max_id + 1 - min_id); + comptime var map = [1]OptionalIndex{set.len} ** (max_id - min_id + 1); inline for (set, 0..) |elem, elem_index| map[comptime elem.id() - min_id] = elem_index; const id_index = reg.id() -% min_id; @@ -360,6 +360,7 @@ pub fn RegisterManager( } else self.getRegIndexAssumeFree(tracked_index, inst); } pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void { + log.debug("getting reg: {}", .{reg}); return self.getRegIndex(indexOfRegIntoTracked(reg) orelse return, inst); } pub fn getKnownReg( diff --git a/src/target.zig b/src/target.zig index 99b9abcab8..8f61b2ba03 100644 --- a/src/target.zig +++ b/src/target.zig @@ -507,7 +507,7 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken if (use_llvm) return .stage2_llvm; if (target.ofmt == .c) return .stage2_c; return switch (target.cpu.arch) { - .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, + .wasm32, .wasm64 => .stage2_wasm, .arm, .armeb, .thumb, .thumbeb => .stage2_arm, .x86_64 => .stage2_x86_64, .x86 => .stage2_x86, @@ -526,7 +526,7 @@ pub fn backendSupportsFeature( feature: Feature, ) bool { return switch (feature) { - .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64, + .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64 or cpu_arch == .riscv64, .panic_unwrap_error => ofmt == .c or use_llvm, .safety_check_formatted => ofmt == .c or use_llvm, .error_return_trace => use_llvm, diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig index 7fc3fbbb4a..21f02b2a3d 100644 --- a/test/behavior/abs.zig +++ b/test/behavior/abs.zig @@ -5,8 +5,8 @@ const expect = std.testing.expect; test "@abs integers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testAbsIntegers(); try testAbsIntegers(); @@ -51,7 +51,6 @@ fn testAbsIntegers() !void { test "@abs unsigned integers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try comptime testAbsUnsignedIntegers(); @@ -92,9 +91,9 @@ fn testAbsUnsignedIntegers() !void { test "@abs floats" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testAbsFloats(f16); try testAbsFloats(f16); @@ -151,8 +150,8 @@ test "@abs int vectors" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testAbsIntVectors(1); try testAbsIntVectors(1); @@ -218,8 +217,8 @@ test "@abs unsigned int vectors" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testAbsUnsignedIntVectors(1); try testAbsUnsignedIntVectors(1); @@ -277,9 +276,9 @@ test "@abs float vectors" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12827 if (builtin.zig_backend == .stage2_llvm and diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 34d76fb4ba..659733962b 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -16,6 +16,7 @@ test "global variable alignment" { } test "large alignment of local constant" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky @@ -25,6 +26,7 @@ test "large alignment of local constant" { } test "slicing array of length 1 can not assume runtime index is always zero" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky @@ -52,6 +54,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { } test "@alignCast pointers" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO var x: u32 align(4) = 1; expectsOnly1(&x); try expect(x == 2); @@ -235,6 +238,7 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { } test "specifying alignment allows pointer cast" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -247,6 +251,7 @@ fn testBytesAlign(b: u8) !void { } test "@alignCast slices" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -265,6 +270,7 @@ fn sliceExpects4(slice: []align(4) u32) void { } test "return error union with 128-bit integer" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -277,6 +283,7 @@ fn give() anyerror!u128 { } test "page aligned array on stack" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -305,6 +312,7 @@ test "function alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // function alignment is a compile error on wasm32/wasm64 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; @@ -418,6 +426,7 @@ test "function callconv expression depends on generic parameter" { } test "runtime-known array index has best alignment possible" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO // take full advantage of over-alignment @@ -478,6 +487,7 @@ const DefaultAligned = struct { }; test "read 128-bit field from default aligned struct in stack memory" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -497,6 +507,7 @@ var default_aligned_global = DefaultAligned{ }; test "read 128-bit field from default aligned struct in global memory" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -506,6 +517,7 @@ test "read 128-bit field from default aligned struct in global memory" { } test "struct field explicit alignment" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -550,6 +562,7 @@ test "align(@alignOf(T)) T does not force resolution of T" { } test "align(N) on functions" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -595,6 +608,7 @@ test "comptime alloc alignment" { } test "@alignCast null" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -610,6 +624,7 @@ test "alignment of slice element" { } test "sub-aligned pointer field access" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; @@ -658,6 +673,7 @@ test "alignment of zero-bit types is respected" { } test "zero-bit fields in extern struct pad fields appropriately" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; diff --git a/test/behavior/alignof.zig b/test/behavior/alignof.zig index e08a42cf19..a3e71a254f 100644 --- a/test/behavior/alignof.zig +++ b/test/behavior/alignof.zig @@ -29,6 +29,8 @@ test "comparison of @alignOf(T) against zero" { } test "correct alignment for elements and slices of aligned array" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var buf: [1024]u8 align(64) = undefined; var start: usize = 1; var end: usize = undefined; diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 6397094398..d524023c9b 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -22,6 +22,7 @@ test "arrays" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var array: [5]u32 = undefined; @@ -49,6 +50,7 @@ fn getArrayLen(a: []const u32) usize { test "array concat with undefined" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -87,6 +89,7 @@ test "array concat with tuple" { test "array init with concat" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = 'a'; var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' }; @@ -96,6 +99,7 @@ test "array init with concat" { test "array init with mult" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = 'a'; var i: [8]u8 = [2]u8{ a, 'b' } ** 4; @@ -159,6 +163,7 @@ test "array len field" { test "array with sentinels" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(is_ct: bool) !void { @@ -226,6 +231,7 @@ test "nested arrays of integers" { test "implicit comptime in array type size" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var arr: [plusOne(10)]bool = undefined; _ = &arr; @@ -239,6 +245,7 @@ fn plusOne(x: u32) u32 { test "single-item pointer to array indexing and slicing" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSingleItemPtrArrayIndexSlice(); try comptime testSingleItemPtrArrayIndexSlice(); @@ -264,6 +271,7 @@ fn doSomeMangling(array: *[4]u8) void { test "implicit cast zero sized array ptr to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var b = "".*; @@ -302,6 +310,7 @@ const Str = struct { a: []Sub }; test "set global var array via slice embedded in struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var s = Str{ .a = s_array[0..] }; @@ -338,6 +347,7 @@ test "read/write through global variable array of struct fields initialized via test "implicit cast single-item pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testImplicitCastSingleItemPtr(); try comptime testImplicitCastSingleItemPtr(); @@ -368,6 +378,7 @@ test "comptime evaluating function that takes array by value" { test "runtime initialize array elem and then implicit cast to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var two: i32 = 2; _ = &two; @@ -378,6 +389,7 @@ test "runtime initialize array elem and then implicit cast to slice" { test "array literal as argument to function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry(two: i32) !void { @@ -406,6 +418,7 @@ test "double nested array to const slice cast in array literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry(two: i32) !void { @@ -492,6 +505,7 @@ test "anonymous literal in array" { test "access the null element of a null terminated array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -511,6 +525,7 @@ test "type deduction for array subscript expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -530,6 +545,7 @@ test "sentinel element count towards the ABI size calculation" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -577,6 +593,7 @@ test "type coercion of anon struct literal to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const U = union { @@ -611,6 +628,7 @@ test "type coercion of pointer to anon struct literal to pointer to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const U = union { @@ -663,6 +681,7 @@ test "array init of container level array variable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { var pair: [2]usize = .{ 1, 2 }; @@ -683,6 +702,8 @@ test "array init of container level array variable" { } test "runtime initialized sentinel-terminated array literal" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var c: u16 = 300; _ = &c; const f = &[_:0x9999]u16{c}; @@ -695,6 +716,7 @@ test "array of array agregate init" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [1]u32{11} ** 10; var b = [1][10]u32{a} ** 2; @@ -745,6 +767,7 @@ test "slicing array of zero-sized values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var arr: [32]u0 = undefined; for (arr[0..]) |*zero| @@ -754,6 +777,8 @@ test "slicing array of zero-sized values" { } test "array init with no result pointer sets field result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { // A function parameter has a result type, but no result pointer. fn f(arr: [1]u32) u32 { @@ -768,6 +793,8 @@ test "array init with no result pointer sets field result types" { } test "runtime side-effects in comptime-known array init" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var side_effects: u4 = 0; const init = [4]u4{ blk: { @@ -792,6 +819,8 @@ test "runtime side-effects in comptime-known array init" { } test "slice initialized through reference to anonymous array init provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var my_u32: u32 = 123; var my_u64: u64 = 456; _ = .{ &my_u32, &my_u64 }; @@ -805,6 +834,8 @@ test "slice initialized through reference to anonymous array init provides resul } test "sentinel-terminated slice initialized through reference to anonymous array init provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var my_u32: u32 = 123; var my_u64: u64 = 456; _ = .{ &my_u32, &my_u64 }; @@ -818,6 +849,8 @@ test "sentinel-terminated slice initialized through reference to anonymous array } test "many-item pointer initialized through reference to anonymous array init provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var my_u32: u32 = 123; var my_u64: u64 = 456; _ = .{ &my_u32, &my_u64 }; @@ -834,6 +867,8 @@ test "many-item pointer initialized through reference to anonymous array init pr } test "many-item sentinel-terminated pointer initialized through reference to anonymous array init provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var my_u32: u32 = 123; var my_u64: u64 = 456; _ = .{ &my_u32, &my_u64 }; @@ -851,6 +886,8 @@ test "many-item sentinel-terminated pointer initialized through reference to ano } test "pointer to array initialized through reference to anonymous array init provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var my_u32: u32 = 123; var my_u64: u64 = 456; _ = .{ &my_u32, &my_u64 }; @@ -864,6 +901,8 @@ test "pointer to array initialized through reference to anonymous array init pro } test "pointer to sentinel-terminated array initialized through reference to anonymous array init provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var my_u32: u32 = 123; var my_u64: u64 = 456; _ = .{ &my_u32, &my_u64 }; @@ -890,6 +929,7 @@ test "copied array element doesn't alias source" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: [10][10]u32 = undefined; @@ -902,6 +942,7 @@ test "copied array element doesn't alias source" { test "array initialized with string literal" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -922,6 +963,7 @@ test "array initialized with string literal" { test "array initialized with array with sentinel" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -969,6 +1011,7 @@ test "accessing multidimensional global array at comptime" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const array = [_][]const []const u8{ @@ -985,6 +1028,7 @@ test "union that needs padding bytes inside an array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const B = union(enum) { D: u8, @@ -1006,6 +1050,7 @@ test "union that needs padding bytes inside an array" { test "runtime index of array of zero-bit values" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var runtime: struct { array: [1]void, index: usize } = undefined; runtime = .{ .array = .{{}}, .index = 0 }; diff --git a/test/behavior/asm.zig b/test/behavior/asm.zig index acb17ea004..e82242f425 100644 --- a/test/behavior/asm.zig +++ b/test/behavior/asm.zig @@ -46,6 +46,7 @@ test "output constraint modifiers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly @@ -69,6 +70,7 @@ test "alternative constraints" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly @@ -87,6 +89,7 @@ test "sized integer/float in asm input" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly @@ -137,6 +140,7 @@ test "struct/array/union types as input values" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index d3f19d396e..830c8a951d 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -15,6 +15,7 @@ test "cmpxchg" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCmpxchg(); try comptime testCmpxchg(); @@ -41,6 +42,7 @@ test "fence" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: i32 = 1234; @fence(.seq_cst); @@ -52,6 +54,7 @@ test "atomicrmw and atomicload" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var data: u8 = 200; try testAtomicRmw(&data); @@ -80,6 +83,7 @@ test "cmpxchg with ptr" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var data1: i32 = 1234; var data2: i32 = 5678; @@ -105,6 +109,7 @@ test "cmpxchg with ignored result" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: i32 = 1234; @@ -149,6 +154,7 @@ test "cmpxchg on a global variable" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // https://github.com/ziglang/zig/issues/10627 @@ -164,6 +170,7 @@ test "atomic load and rmw with enum" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Value = enum(u8) { a, b, c }; var x = Value.a; @@ -181,6 +188,7 @@ test "atomic store" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u32 = 0; @atomicStore(u32, &x, 1, .seq_cst); @@ -194,6 +202,7 @@ test "atomic store comptime" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testAtomicStore(); try testAtomicStore(); @@ -212,6 +221,7 @@ test "atomicrmw with floats" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // https://github.com/ziglang/zig/issues/10627 @@ -241,6 +251,7 @@ test "atomicrmw with ints" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) { // https://github.com/ziglang/zig/issues/16846 @@ -390,6 +401,7 @@ test "atomics with different types" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testAtomicsWithType(bool, true, false); @@ -419,6 +431,7 @@ test "return @atomicStore, using it as a void value" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const A = struct { diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index c9abaf9c8b..eabac35787 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -16,6 +16,8 @@ test "empty function with comments" { } test "truncate" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(testTruncate(0x10fd) == 0xfd); comptime assert(testTruncate(0x10fd) == 0xfd); } @@ -25,6 +27,7 @@ fn testTruncate(x: u32) u8 { test "truncate to non-power-of-two integers" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTrunc(u32, u1, 0b10101, 0b1); try testTrunc(u32, u1, 0b10110, 0b0); @@ -42,6 +45,7 @@ test "truncate to non-power-of-two integers from 128-bit" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01); try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00); @@ -220,6 +224,7 @@ const OpaqueB = opaque {}; test "opaque types" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(*OpaqueA != *OpaqueB); @@ -371,6 +376,7 @@ test "take address of parameter" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTakeAddressOfParameter(12.34); } @@ -395,6 +401,7 @@ test "array 2D const double ptr" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const rect_2d_vertexes = [_][1]f32{ [_]f32{1.0}, @@ -407,6 +414,7 @@ test "array 2D const double ptr with offset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const rect_2d_vertexes = [_][2]f32{ [_]f32{ 3.0, 4.239 }, @@ -419,6 +427,7 @@ test "array 3D const double ptr with offset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const rect_3d_vertexes = [_][2][2]f32{ [_][2]f32{ @@ -474,6 +483,7 @@ fn testStructInFn() !void { test "fn call returning scalar optional in equality expression" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(getNull() == null); } @@ -484,6 +494,7 @@ fn getNull() ?*i32 { test "global variable assignment with optional unwrapping with var initialized to undefined" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { var data: i32 = 1234; @@ -502,6 +513,7 @@ var global_foo: *i32 = undefined; test "peer result location with typed parent, runtime condition, comptime prongs" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(arg: i32) i32 { @@ -581,6 +593,7 @@ test "equality compare fn ptrs" { test "self reference through fn ptr field" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const A = struct { @@ -613,6 +626,7 @@ var global_ptr = &gdt[0]; test "global constant is loaded with a runtime-known index" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -631,6 +645,7 @@ test "global constant is loaded with a runtime-known index" { test "multiline string literal is null terminated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const s1 = \\one @@ -645,6 +660,7 @@ test "string escapes" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expectEqualStrings("\"", "\x22"); try expectEqualStrings("\'", "\x27"); @@ -674,6 +690,7 @@ test "string concatenation" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = "OK" ++ " IT " ++ "WORKED"; const b = "OK IT WORKED"; @@ -697,6 +714,7 @@ test "result location is optional inside error union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const x = maybe(true) catch unreachable; try expect(x.? == 42); @@ -712,6 +730,7 @@ fn maybe(x: bool) anyerror!?u32 { test "auto created variables have correct alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(str: [*]const u8) u32 { @@ -733,6 +752,7 @@ test "extern variable with non-pointer opaque type" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @export(var_to_export, .{ .name = "opaque_extern_var" }); try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42); @@ -776,6 +796,7 @@ test "discarding the result of various expressions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() !u32 { @@ -817,6 +838,7 @@ test "labeled block implicitly ends in a break" { test "catch in block has correct result location" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn open() error{A}!@This() { @@ -848,6 +870,7 @@ test "labeled block with runtime branch forwards its result location type to bre test "try in labeled block doesn't cast to wrong type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -874,6 +897,7 @@ test "weird array and tuple initializations" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = enum { a, b }; const S = struct { e: E }; @@ -992,6 +1016,7 @@ comptime { test "switch inside @as gets correct type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u32 = 0; _ = &a; @@ -1058,6 +1083,7 @@ test "returning an opaque type from a function" { test "orelse coercion as function argument" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Loc = struct { start: i32 = -1 }; const Container = struct { @@ -1075,6 +1101,8 @@ test "orelse coercion as function argument" { } test "runtime-known globals initialized with undefined" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { var array: [10]u32 = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var vp: [*]u32 = undefined; @@ -1095,6 +1123,7 @@ test "arrays and vectors with big integers" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO: only aarch64-windows didn't pass in the PR that added this code. // figure out why if you can run this target. @@ -1119,6 +1148,8 @@ test "pointer to struct literal with runtime field is constant" { } test "integer compare" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTestSigned(comptime T: type) !void { var z: T = 0; @@ -1215,6 +1246,8 @@ test "pointer to tuple field can be dereferenced at comptime" { } test "proper value is returned from labeled block" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn hash(v: *u32, key: anytype) void { const Key = @TypeOf(key); @@ -1281,6 +1314,7 @@ test "break out of block based on comptime known values" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const source = "A-"; @@ -1317,6 +1351,7 @@ test "allocation and looping over 3-byte integer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .macos) { return error.SkipZigTest; // TODO @@ -1350,6 +1385,8 @@ test "allocation and looping over 3-byte integer" { } test "loading array from struct is not optimized away" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { arr: [1]u32 = .{0}, fn doTheTest(self: *@This()) !void { diff --git a/test/behavior/bit_shifting.zig b/test/behavior/bit_shifting.zig index 216d9eeaa5..9d203dcfe3 100644 --- a/test/behavior/bit_shifting.zig +++ b/test/behavior/bit_shifting.zig @@ -65,6 +65,7 @@ test "sharded table" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // realistic 16-way sharding try testShardedTable(u32, 4, 8); @@ -116,6 +117,7 @@ test "Saturating Shift Left where lhs is of a computed type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn getIntShiftType(comptime T: type) type { diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index a274553665..28c797cef3 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -10,6 +10,7 @@ const native_endian = builtin.target.cpu.arch.endian(); test "@bitCast iX -> uX (32, 64)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bit_values = [_]usize{ 32, 64 }; @@ -24,6 +25,7 @@ test "@bitCast iX -> uX (8, 16, 128)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bit_values = [_]usize{ 8, 16, 128 }; @@ -39,6 +41,7 @@ test "@bitCast iX -> uX exotic integers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 }; @@ -83,6 +86,7 @@ test "bitcast uX to bytes" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 }; inline for (bit_values) |bits| { @@ -161,6 +165,7 @@ test "@bitCast packed structs at runtime and comptime" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Full = packed struct { number: u16, @@ -187,6 +192,7 @@ test "@bitCast packed structs at runtime and comptime" { test "@bitCast extern structs at runtime and comptime" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Full = extern struct { number: u16, @@ -221,6 +227,7 @@ test "bitcast packed struct to integer and back" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const LevelUpMove = packed struct { move_id: u9, @@ -243,6 +250,7 @@ test "bitcast packed struct to integer and back" { test "implicit cast to error union by returning" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -272,6 +280,8 @@ test "comptime bitcast used in expression has the correct type" { } test "bitcast passed as tuple element" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn foo(args: anytype) !void { comptime assert(@TypeOf(args[0]) == f32); @@ -282,6 +292,8 @@ test "bitcast passed as tuple element" { } test "triple level result location with bitcast sandwich passed as tuple element" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn foo(args: anytype) !void { comptime assert(@TypeOf(args[0]) == f64); @@ -299,6 +311,7 @@ test "@bitCast packed struct of floats" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Foo = packed struct { a: f16 = 0, @@ -337,6 +350,7 @@ test "comptime @bitCast packed struct to int and back" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and native_endian == .big) { // https://github.com/ziglang/zig/issues/13782 @@ -401,6 +415,7 @@ test "bitcast vector to integer and back" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const arr: [16]bool = [_]bool{ true, false } ++ [_]bool{true} ** 14; var x: @Vector(16, bool) = @splat(true); @@ -426,6 +441,7 @@ test "bitcast nan float does not modify signaling bit" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO: https://github.com/ziglang/zig/issues/14366 if (builtin.zig_backend == .stage2_llvm and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; @@ -482,6 +498,7 @@ test "@bitCast of packed struct of bools all true" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const P = packed struct { b0: bool, diff --git a/test/behavior/bitreverse.zig b/test/behavior/bitreverse.zig index 259e6b29ec..55a3d580ff 100644 --- a/test/behavior/bitreverse.zig +++ b/test/behavior/bitreverse.zig @@ -16,6 +16,7 @@ test "@bitReverse" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testBitReverse(); try testBitReverse(); @@ -121,6 +122,7 @@ test "bitReverse vectors u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector8(); try vector8(); @@ -141,6 +143,7 @@ test "bitReverse vectors u16" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector16(); try vector16(); @@ -161,6 +164,7 @@ test "bitReverse vectors u24" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector24(); try vector24(); diff --git a/test/behavior/bool.zig b/test/behavior/bool.zig index 608fb20ca7..72c1dff336 100644 --- a/test/behavior/bool.zig +++ b/test/behavior/bool.zig @@ -9,6 +9,8 @@ test "bool literals" { } test "cast bool to int" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const t = true; const f = false; try expectEqual(@as(u32, 1), @intFromBool(t)); diff --git a/test/behavior/builtin_functions_returning_void_or_noreturn.zig b/test/behavior/builtin_functions_returning_void_or_noreturn.zig index 7b8f23c262..712a24b950 100644 --- a/test/behavior/builtin_functions_returning_void_or_noreturn.zig +++ b/test/behavior/builtin_functions_returning_void_or_noreturn.zig @@ -10,8 +10,8 @@ test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var val: u8 = undefined; try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered)); diff --git a/test/behavior/byteswap.zig b/test/behavior/byteswap.zig index 182948416c..fd7e2af850 100644 --- a/test/behavior/byteswap.zig +++ b/test/behavior/byteswap.zig @@ -3,6 +3,8 @@ const builtin = @import("builtin"); const expect = std.testing.expect; test "@byteSwap integers" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) { // TODO: Remove when self-hosted wasm supports more types for byteswap const ByteSwapIntTest = struct { @@ -118,6 +120,7 @@ test "@byteSwap vectors u16" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector16(); try vector16(); @@ -138,6 +141,7 @@ test "@byteSwap vectors u24" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector24(); try vector24(); diff --git a/test/behavior/byval_arg_var.zig b/test/behavior/byval_arg_var.zig index 01b5f90ef7..ed0fde991f 100644 --- a/test/behavior/byval_arg_var.zig +++ b/test/behavior/byval_arg_var.zig @@ -5,6 +5,7 @@ var result: []const u8 = "wrong"; test "pass string literal byvalue to a generic var param" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; start(); blowUpStack(10); diff --git a/test/behavior/call.zig b/test/behavior/call.zig index c1ae3b66c6..2f737f098c 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -60,6 +60,7 @@ test "tuple parameters" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const add = struct { fn add(a: i32, b: i32) i32 { @@ -93,6 +94,7 @@ test "result location of function call argument through runtime condition and st if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = enum { a, b }; const S = struct { @@ -112,6 +114,7 @@ test "result location of function call argument through runtime condition and st test "function call with 40 arguments" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(thirty_nine: i32) !void { @@ -271,6 +274,7 @@ test "forced tail call" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) { // Only attempt this test on targets we know have tail call support in LLVM. @@ -306,6 +310,7 @@ test "inline call preserves tail call" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) { // Only attempt this test on targets we know have tail call support in LLVM. @@ -339,6 +344,7 @@ test "inline call preserves tail call" { test "inline call doesn't re-evaluate non generic struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(f: struct { a: u8, b: u8 }) !void { @@ -405,6 +411,7 @@ test "recursive inline call with comptime known argument" { test "inline while with @call" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn inc(a: *u32) void { @@ -420,6 +427,8 @@ test "inline while with @call" { } test "method call as parameter type" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) { return y; @@ -437,6 +446,7 @@ test "non-anytype generic parameters provide result type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn f(comptime T: type, y: T) !void { @@ -467,6 +477,7 @@ test "argument to generic function has correct result type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(_: anytype, e: enum { a, b }) bool { @@ -502,6 +513,8 @@ test "call inline fn through pointer" { } test "call coerced function" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const T = struct { x: f64, const T = @This(); diff --git a/test/behavior/call_tail.zig b/test/behavior/call_tail.zig index 24aab2a01e..3cb858a10b 100644 --- a/test/behavior/call_tail.zig +++ b/test/behavior/call_tail.zig @@ -31,6 +31,8 @@ noinline fn insertionSort(data: []u64) void { } test "arguments pointed to on stack into tailcall" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + switch (builtin.cpu.arch) { .wasm32, .mips, diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 2f47155cc4..46cf272e57 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -24,6 +24,7 @@ test "peer type resolution: ?T and T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(peerTypeTAndOptionalT(true, false).? == 0); try expect(peerTypeTAndOptionalT(false, false).? == 3); @@ -56,6 +57,8 @@ test "@intCast to comptime_int" { } test "implicit cast comptime numbers to any type when the value fits" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const a: u64 = 255; var b: u8 = a; _ = &b; @@ -103,6 +106,7 @@ test "@floatFromInt" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -126,6 +130,7 @@ test "@floatFromInt(f80)" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(comptime Int: type) !void { @@ -160,6 +165,7 @@ test "@intFromFloat" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testIntFromFloats(); try comptime testIntFromFloats(); @@ -182,6 +188,7 @@ fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void { test "implicitly cast indirect pointer to maybe-indirect pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Self = @This(); @@ -242,6 +249,7 @@ test "coerce undefined to optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(MakeType(void).getNull() == null); try expect(MakeType(void).getNonNull() != null); @@ -262,6 +270,7 @@ fn MakeType(comptime T: type) type { test "implicit cast from *[N]T to [*c]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; var y: [*c]u16 = &x; @@ -299,6 +308,7 @@ test "peer result null and comptime_int" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn blah(n: i32) ?i32 { @@ -323,6 +333,7 @@ test "peer result null and comptime_int" { test "*const ?[*]const T to [*c]const [*c]const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var array = [_]u8{ 'o', 'k' }; const opt_array_ptr: ?[*]const u8 = &array; @@ -336,6 +347,7 @@ test "array coercion to undefined at runtime" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @setRuntimeSafety(true); @@ -366,6 +378,7 @@ test "return u8 coercing into ?u32 return type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -400,6 +413,7 @@ test "peer type unsigned int to signed" { test "expected [*c]const u8, found [*:0]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [*:0]const u8 = "hello"; _ = &a; @@ -413,6 +427,7 @@ test "explicit cast from integer to error type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCastIntToErr(error.ItBroke); try comptime testCastIntToErr(error.ItBroke); @@ -442,6 +457,7 @@ test "implicitly cast from T to anyerror!?T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try castToOptionalTypeError(1); try comptime castToOptionalTypeError(1); @@ -467,6 +483,7 @@ fn castToOptionalTypeError(z: i32) !void { test "implicitly cast from [0]T to anyerror![]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCastZeroArrayToErrSliceMut(); try comptime testCastZeroArrayToErrSliceMut(); @@ -484,6 +501,7 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() anyerror!void { @@ -540,6 +558,7 @@ fn testCastConstArrayRefToConstSlice() !void { test "peer type resolution: error and [N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); @@ -564,6 +583,7 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { test "single-item pointer of array to slice to unknown length pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCastPtrOfArrayToSliceAndPtr(); try comptime testCastPtrOfArrayToSliceAndPtr(); @@ -593,6 +613,7 @@ fn testCastPtrOfArrayToSliceAndPtr() !void { test "cast *[1][*]const u8 to [*]const ?[*]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const window_name = [1][*]const u8{"window name"}; const x: [*]const ?[*]const u8 = &window_name; @@ -605,6 +626,7 @@ test "@intCast on vector" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -639,6 +661,7 @@ test "@floatCast cast down" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var double: f64 = 0.001534; @@ -656,6 +679,7 @@ test "@floatCast cast down" { test "peer type resolution: unreachable, error set, unreachable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Error = error{ FileDescriptorAlreadyPresentInSet, @@ -750,6 +774,7 @@ test "peer type resolution: error union and error set" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a: error{Three} = undefined; const b: error{ One, Two }!u32 = undefined; @@ -816,6 +841,7 @@ test "peer cast *[0]T to E![]const T" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buffer: [5]u8 = "abcde".*; const buf: anyerror![]const u8 = buffer[0..]; @@ -831,6 +857,7 @@ test "peer cast *[0]T to []const T" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buffer: [5]u8 = "abcde".*; const buf: []const u8 = buffer[0..]; @@ -854,6 +881,7 @@ test "peer resolution of string literals" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const E = enum { a, b, c, d }; @@ -875,6 +903,7 @@ test "peer resolution of string literals" { test "peer cast [:x]T to []T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -891,6 +920,7 @@ test "peer cast [:x]T to []T" { test "peer cast [N:x]T to [N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -907,6 +937,7 @@ test "peer cast [N:x]T to [N]T" { test "peer cast *[N:x]T to *[N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -922,6 +953,7 @@ test "peer cast *[N:x]T to *[N]T" { test "peer cast [*:x]T to [*]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -942,6 +974,7 @@ test "peer cast [:x]T to [*:x]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -962,6 +995,7 @@ test "peer cast [:x]T to [*:x]T" { test "peer type resolution implicit cast to return type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -982,6 +1016,7 @@ test "peer type resolution implicit cast to return type" { test "peer type resolution implicit cast to variable type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1007,6 +1042,7 @@ test "variable initialization uses result locations properly with regards to the test "cast between C pointer with different but compatible types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(arg: [*]c_ushort) u16 { @@ -1024,6 +1060,7 @@ test "cast between C pointer with different but compatible types" { test "peer type resolve string lit with sentinel-terminated mutable slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var array: [4:0]u8 = undefined; array[4] = 0; // TODO remove this when #4372 is solved @@ -1090,6 +1127,7 @@ test "implicit cast from [*]T to ?*anyopaque" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [_]u8{ 3, 2, 1 }; var runtime_zero: usize = 0; @@ -1120,6 +1158,7 @@ fn foobar(func: PFN_void) !void { test "cast function with an opaque parameter" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) { // https://github.com/ziglang/zig/issues/16845 @@ -1152,6 +1191,7 @@ test "implicit ptr to *anyopaque" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u32 = 1; const ptr: *align(@alignOf(u32)) anyopaque = &a; @@ -1165,6 +1205,7 @@ test "implicit ptr to *anyopaque" { test "return null from fn () anyerror!?&T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = returnNullFromOptionalTypeErrorRef(); const b = returnNullLitFromOptionalTypeErrorRef(); @@ -1181,6 +1222,7 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { test "peer type resolution: [0]u8 and []const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); @@ -1201,6 +1243,7 @@ test "implicitly cast from [N]T to ?[]const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi")); @@ -1215,6 +1258,7 @@ test "cast u128 to f128 and back" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testCast128(); try testCast128(); @@ -1236,6 +1280,7 @@ test "implicit cast from *[N]T to ?[*]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: ?[*]u16 = null; var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; @@ -1251,6 +1296,7 @@ test "implicit cast from *T to ?*anyopaque" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u8 = 1; incrementVoidPtrValue(&a); @@ -1264,6 +1310,7 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void { test "implicit cast *[0]T to E![]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x = @as(anyerror![]const u8, &[0]u8{}); _ = &x; @@ -1285,6 +1332,7 @@ test "*const [N]null u8 to ?[]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1321,6 +1369,7 @@ test "assignment to optional pointer result loc" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo: struct { ptr: ?*anyopaque } = .{ .ptr = &global_struct }; _ = &foo; @@ -1328,6 +1377,8 @@ test "assignment to optional pointer result loc" { } test "cast between *[N]void and []void" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var a: [4]void = undefined; const b: []void = &a; try expect(b.len == 4); @@ -1353,6 +1404,7 @@ test "cast f16 to wider types" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1373,6 +1425,7 @@ test "cast f128 to narrower types" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1391,6 +1444,7 @@ test "peer type resolution: unreachable, null, slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(num: usize, word: []const u8) !void { @@ -1431,6 +1485,7 @@ test "cast compatible optional types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: ?[:0]const u8 = null; _ = &a; @@ -1441,6 +1496,7 @@ test "cast compatible optional types" { test "coerce undefined single-item pointer of array to error union of slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = @as([*]u8, undefined)[0..0]; var b: error{a}![]const u8 = a; @@ -1464,6 +1520,7 @@ test "coerce between pointers of compatible differently-named floats" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/12396 @@ -1518,6 +1575,7 @@ test "cast typed undefined to int" { test "implicit cast from [:0]T to [*c]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [:0]const u8 = "foo"; _ = &a; @@ -1541,6 +1599,7 @@ test "bitcast packed struct with u0" { test "optional pointer coerced to optional allowzero pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var p: ?*u32 = undefined; var q: ?*allowzero u32 = undefined; @@ -1557,6 +1616,8 @@ test "optional slice coerced to allowzero many pointer" { } test "optional slice passed as parameter coerced to allowzero many pointer" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const ns = struct { const Color = struct { r: u8, @@ -1576,6 +1637,8 @@ test "optional slice passed as parameter coerced to allowzero many pointer" { } test "single item pointer to pointer to array to slice" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var x: i32 = 1234; try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234); const z1 = @as([]const i32, @as(*[1]i32, &x)); @@ -1583,6 +1646,8 @@ test "single item pointer to pointer to array to slice" { } test "peer type resolution forms error union" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var foo: i32 = 123; _ = &foo; const result = if (foo < 0) switch (-foo) { @@ -1616,6 +1681,8 @@ test "@volatileCast without a result location" { } test "coercion from single-item pointer to @as to slice" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var x: u32 = 1; // Why the following line gets a compile error? @@ -1628,6 +1695,7 @@ test "peer type resolution: const sentinel slice and mutable non-sentinel slice" if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(comptime T: type, comptime s: T) !void { @@ -1658,6 +1726,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const i: u8 = 100; var f: f32 = 1.234; @@ -1680,6 +1749,7 @@ test "peer type resolution: same array type with sentinel" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [2:0]u32 = .{ 0, 1 }; var b: [2:0]u32 = .{ 2, 3 }; @@ -1702,6 +1772,7 @@ test "peer type resolution: array with sentinel and array without sentinel" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [2:0]u32 = .{ 0, 1 }; var b: [2]u32 = .{ 2, 3 }; @@ -1724,6 +1795,7 @@ test "peer type resolution: array and vector with same child type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var arr: [2]u32 = .{ 0, 1 }; var vec: @Vector(2, u32) = .{ 2, 3 }; @@ -1747,6 +1819,7 @@ test "peer type resolution: array with smaller child type and vector with larger if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var arr: [2]u8 = .{ 0, 1 }; var vec: @Vector(2, u64) = .{ 2, 3 }; @@ -1769,6 +1842,7 @@ test "peer type resolution: error union and optional of same type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = error{Foo}; var a: E!*u8 = error.Foo; @@ -1792,6 +1866,7 @@ test "peer type resolution: C pointer and @TypeOf(null)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [*c]c_int = 0x1000; _ = &a; @@ -1814,6 +1889,7 @@ test "peer type resolution: three-way resolution combines error set and optional if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = error{Foo}; var a: E = error.Foo; @@ -1858,6 +1934,7 @@ test "peer type resolution: vector and optional vector" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: ?@Vector(3, u32) = .{ 0, 1, 2 }; var b: @Vector(3, u32) = .{ 3, 4, 5 }; @@ -1880,6 +1957,7 @@ test "peer type resolution: optional fixed-width int and comptime_int" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: ?i32 = 42; _ = &a; @@ -1902,6 +1980,7 @@ test "peer type resolution: array and tuple" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var arr: [3]i32 = .{ 1, 2, 3 }; _ = &arr; @@ -1926,6 +2005,7 @@ test "peer type resolution: vector and tuple" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var vec: @Vector(3, i32) = .{ 1, 2, 3 }; _ = &vec; @@ -1950,6 +2030,7 @@ test "peer type resolution: vector and array and tuple" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var vec: @Vector(2, i8) = .{ 10, 20 }; var arr: [2]i8 = .{ 30, 40 }; @@ -2034,6 +2115,7 @@ test "peer type resolution: tuple pointer and optional slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // Miscompilation on Intel's OpenCL CPU runtime. if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky @@ -2058,6 +2140,7 @@ test "peer type resolution: many compatible pointers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf = "foo-3".*; @@ -2125,6 +2208,7 @@ test "peer type resolution: tuples with comptime fields" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = .{ 1, 2 }; const b = .{ @as(u32, 3), @as(i16, 4) }; @@ -2156,6 +2240,7 @@ test "peer type resolution: C pointer and many pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf = "hello".*; @@ -2179,6 +2264,7 @@ test "peer type resolution: pointer attributes are combined correctly" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf_a align(4) = "foo".*; var buf_b align(4) = "bar".*; @@ -2222,6 +2308,7 @@ test "peer type resolution: arrays of compatible types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var e0: u8 = 3; var e1: u8 = 2; @@ -2239,6 +2326,7 @@ test "cast builtins can wrap result in optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const MyEnum = enum(u32) { _ }; @@ -2276,6 +2364,7 @@ test "cast builtins can wrap result in error union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const MyEnum = enum(u32) { _ }; @@ -2314,6 +2403,7 @@ test "cast builtins can wrap result in error union and optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const MyEnum = enum(u32) { _ }; @@ -2354,6 +2444,7 @@ test "@floatCast on vector" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -2394,6 +2485,7 @@ test "@ptrFromInt on vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -2417,6 +2509,7 @@ test "@intFromPtr on vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -2441,6 +2534,7 @@ test "@floatFromInt on vector" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -2460,6 +2554,7 @@ test "@intFromFloat on vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -2480,6 +2575,7 @@ test "@intFromBool on vector" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) @@ -2503,6 +2599,7 @@ test "@intFromBool on vector" { test "numeric coercions with undefined" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const from: i32 = undefined; var to: f32 = from; @@ -2513,6 +2610,7 @@ test "numeric coercions with undefined" { test "15-bit int to float" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u15 = 42; _ = &a; @@ -2525,6 +2623,7 @@ test "@as does not corrupt values with incompatible representations" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const x: f32 = @as(f16, blk: { if (false) { @@ -2540,6 +2639,7 @@ test "result information is preserved through many nested structures" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -2566,6 +2666,7 @@ test "@intCast vector of signed integer" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: @Vector(4, i32) = .{ 1, 2, 3, 4 }; _ = &x; @@ -2586,6 +2687,7 @@ test "implicit cast from ptr to tuple to ptr to struct" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const ComptimeReason = union(enum) { c_import: struct { diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index 065710c5c2..67834385d1 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -9,6 +9,7 @@ test "@intCast i32 to u7" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u128 = maxInt(u128); var y: i32 = 120; @@ -34,6 +35,8 @@ test "coerce i8 to i32 and @intCast back" { } test "coerce non byte-sized integers accross 32bits boundary" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + { var v: u21 = 6417; _ = &v; @@ -163,6 +166,8 @@ const Piece = packed struct { }; test "load non byte-sized optional value" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // Originally reported at https://github.com/ziglang/zig/issues/14200 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -178,6 +183,8 @@ test "load non byte-sized optional value" { } test "load non byte-sized value in struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -215,6 +222,7 @@ test "load non byte-sized value in union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // note: this bug is triggered by the == operator, expectEqual will hide it // using ptrCast not to depend on unitialised memory state diff --git a/test/behavior/comptime_memory.zig b/test/behavior/comptime_memory.zig index 968b7be79d..597ba62dd4 100644 --- a/test/behavior/comptime_memory.zig +++ b/test/behavior/comptime_memory.zig @@ -408,6 +408,8 @@ test "mutate entire slice at comptime" { } test "dereference undefined pointer to zero-bit type" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const p0: *void = undefined; try testing.expectEqual({}, p0.*); @@ -513,5 +515,7 @@ fn fieldPtrTest() u32 { return a.value; } test "pointer in aggregate field can mutate comptime state" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try comptime std.testing.expect(fieldPtrTest() == 2); } diff --git a/test/behavior/const_slice_child.zig b/test/behavior/const_slice_child.zig index 35bc007d84..0f81fdc935 100644 --- a/test/behavior/const_slice_child.zig +++ b/test/behavior/const_slice_child.zig @@ -10,6 +10,7 @@ test "const slice child" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const strs = [_][*]const u8{ "one", "two", "three" }; argv = &strs; diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index 593282ac59..ba0d949a7d 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -53,6 +53,7 @@ test "return variable while defer expression in scope to modify it" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -94,6 +95,7 @@ test "mixing normal and error defers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(runSomeErrorDefers(true) catch unreachable); try expect(result[0] == 'c'); @@ -114,6 +116,7 @@ test "errdefer with payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() !i32 { @@ -136,6 +139,7 @@ test "reference to errdefer payload" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() !i32 { @@ -158,6 +162,7 @@ test "reference to errdefer payload" { test "simple else prong doesn't emit an error for unreachable else prong" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() error{Foo}!void { diff --git a/test/behavior/destructure.zig b/test/behavior/destructure.zig index 43ddbb7a4d..3164d25187 100644 --- a/test/behavior/destructure.zig +++ b/test/behavior/destructure.zig @@ -23,6 +23,8 @@ test "simple destructure" { } test "destructure with comptime syntax" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { { diff --git a/test/behavior/duplicated_test_names.zig b/test/behavior/duplicated_test_names.zig index 81b9ebdf50..9453f22ae1 100644 --- a/test/behavior/duplicated_test_names.zig +++ b/test/behavior/duplicated_test_names.zig @@ -16,6 +16,7 @@ test "thingy" {} test thingy { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (thingy(1, 2) != 3) unreachable; } diff --git a/test/behavior/empty_tuple_fields.zig b/test/behavior/empty_tuple_fields.zig index a7a3d27e02..788ed19e5e 100644 --- a/test/behavior/empty_tuple_fields.zig +++ b/test/behavior/empty_tuple_fields.zig @@ -5,6 +5,7 @@ test "empty file level struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = @import("empty_file_level_struct.zig"); const info = @typeInfo(T); @@ -17,6 +18,7 @@ test "empty file level union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = @import("empty_file_level_union.zig"); const info = @typeInfo(T); diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig index f05feacfaf..a42dfda7e1 100644 --- a/test/behavior/empty_union.zig +++ b/test/behavior/empty_union.zig @@ -48,6 +48,8 @@ test "empty extern union" { } test "empty union passed as argument" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const U = union(enum) { fn f(u: @This()) void { switch (u) {} @@ -57,6 +59,8 @@ test "empty union passed as argument" { } test "empty enum passed as argument" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const E = enum { fn f(e: @This()) void { switch (e) {} diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 77b22f82aa..dd2d83a289 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -610,6 +610,7 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { test "enum with specified tag values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testEnumWithSpecifiedTagValues(MultipleChoice.C); try comptime testEnumWithSpecifiedTagValues(MultipleChoice.C); @@ -618,6 +619,7 @@ test "enum with specified tag values" { test "non-exhaustive enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const E = enum(u8) { a, b, _ }; @@ -682,6 +684,7 @@ test "empty non-exhaustive enum" { test "single field non-exhaustive enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const E = enum(u8) { a, _ }; @@ -746,6 +749,7 @@ test "cast integer literal to enum" { test "enum with specified and unspecified tag values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); try comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); @@ -854,6 +858,8 @@ fn doALoopThing(id: EnumWithOneMember) void { } test "comparison operator on enum with one member is comptime-known" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + doALoopThing(EnumWithOneMember.Eof); } @@ -907,6 +913,7 @@ test "enum literal casting to tagged union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Arch = union(enum) { x86_64, @@ -933,6 +940,7 @@ const Bar = enum { A, B, C, D }; test "enum literal casting to error union with payload enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var bar: error{B}!Bar = undefined; bar = .B; // should never cast to the error set @@ -944,6 +952,7 @@ test "constant enum initialization with differing sizes" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try test3_1(test3_foo); try test3_2(test3_bar); @@ -987,6 +996,7 @@ test "@tagName" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); @@ -1003,6 +1013,7 @@ test "@tagName non-exhaustive enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); comptime assert(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); @@ -1014,6 +1025,7 @@ test "@tagName is null-terminated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(n: BareNumber) !void { @@ -1029,6 +1041,7 @@ test "tag name with assigned enum values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const LocalFoo = enum(u8) { A = 1, @@ -1052,6 +1065,7 @@ test "tag name with signed enum values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const LocalFoo = enum(isize) { alfa = 62, @@ -1068,6 +1082,7 @@ test "enum literal casting to optional" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var bar: ?Bar = undefined; bar = .B; @@ -1096,6 +1111,7 @@ test "bit field access with enum fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var data = bit_field_1; try expect(getA(&data) == A.Two); @@ -1136,6 +1152,7 @@ test "tag name functions are unique" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { const E = enum { a, b }; @@ -1212,6 +1229,8 @@ test "enum tag from a local variable" { } test "auto-numbered enum with signed tag type" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const E = enum(i32) { a, b }; try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a)); @@ -1266,6 +1285,7 @@ test "matching captures causes enum equivalence" { test "large enum field values" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { const E = enum(u64) { min = std.math.minInt(u64), max = std.math.maxInt(u64) }; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 7703a02f68..b579f1478e 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -31,6 +31,7 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void { test "error binary operator" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = errBinaryOperatorG(true) catch 3; const b = errBinaryOperatorG(false) catch 3; @@ -62,12 +63,14 @@ pub fn baz() anyerror!i32 { test "error wrapping" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect((baz() catch unreachable) == 15); } test "unwrap simple value from error" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const i = unwrapSimpleValueFromErrorDo() catch unreachable; try expect(i == 13); @@ -78,6 +81,7 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize { test "error return in assignment" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; doErrReturnInAssignment() catch unreachable; } @@ -100,6 +104,7 @@ test "syntax: optional operator in front of error union operator" { test "widen cast integer payload of error union function call" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn errorable() !u64 { @@ -124,6 +129,7 @@ test "debug info for optional error set" { test "implicit cast to optional to error union to return result loc" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -235,6 +241,8 @@ fn testExplicitErrorSetCast(set1: Set1) !void { } test "@errorCast on error unions" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { { @@ -262,6 +270,7 @@ test "@errorCast on error unions" { test "comptime test error for empty error set" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testComptimeTestErrorEmptySet(1234); try comptime testComptimeTestErrorEmptySet(1234); @@ -297,6 +306,8 @@ test "inferred empty error set comptime catch" { } test "error inference with an empty set" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { const Struct = struct { pub fn func() (error{})!usize { @@ -319,6 +330,7 @@ test "error inference with an empty set" { test "error union peer type resolution" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testErrorUnionPeerTypeResolution(1); } @@ -350,6 +362,7 @@ fn quux_1() !i32 { test "error: Zero sized error set returned with value payload crash" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; _ = try foo3(0); _ = try comptime foo3(0); @@ -363,6 +376,7 @@ fn foo3(b: usize) Error!usize { test "error: Infer error set from literals" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; _ = nullLiteral("n") catch |err| handleErrors(err); _ = floatLiteral("n") catch |err| handleErrors(err); @@ -402,6 +416,7 @@ test "nested error union function call in optional unwrap" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Foo = struct { @@ -448,6 +463,7 @@ test "nested error union function call in optional unwrap" { test "return function call to error set from error union function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn errorable() anyerror!i32 { @@ -466,6 +482,7 @@ test "optional error set is the same size as error set" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; comptime assert(@sizeOf(?anyerror) == @sizeOf(anyerror)); comptime assert(@alignOf(?anyerror) == @alignOf(anyerror)); @@ -481,6 +498,7 @@ test "optional error set is the same size as error set" { test "nested catch" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -506,6 +524,7 @@ test "nested catch" { test "function pointer with return type that is error union with payload which is pointer of parent struct" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Foo = struct { @@ -531,6 +550,7 @@ test "return result loc as peer result loc in inferred error set function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -562,6 +582,7 @@ test "error payload type is correctly resolved" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const MyIntWrapper = struct { const Self = @This(); @@ -592,6 +613,7 @@ test "@errorName" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(mem.eql(u8, @errorName(error.AnError), "AnError")); try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); @@ -606,6 +628,7 @@ test "@errorName sentinel length matches slice length" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const name = testBuiltinErrorName(error.FooBar); const length: usize = 6; @@ -700,6 +723,7 @@ test "error union payload is properly aligned" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u128, @@ -731,6 +755,7 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" { test "simple else prong allowed even when all errors handled" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() !u8 { @@ -759,6 +784,7 @@ test "pointer to error union payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var err_union: anyerror!u8 = 15; @@ -792,6 +818,7 @@ test "error union of noreturn used with if" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; if (NoReturn.loop()) { @@ -806,6 +833,7 @@ test "error union of noreturn used with try" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; const err = NoReturn.testTry(); @@ -817,6 +845,7 @@ test "error union of noreturn used with catch" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; const err = NoReturn.testCatch(); @@ -828,6 +857,7 @@ test "alignment of wrapping an error union payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const I = extern struct { x: i128 }; @@ -843,6 +873,7 @@ test "alignment of wrapping an error union payload" { test "compare error union and error set" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: anyerror = error.Foo; var b: anyerror!u32 = error.Bar; @@ -881,6 +912,7 @@ test "error from comptime string" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const name = "Weird error name!"; const S = struct { @@ -904,6 +936,7 @@ test "field access of anyerror results in smaller error set" { test "optional error union return type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() ?anyerror!u32 { @@ -918,6 +951,7 @@ test "optional error union return type" { test "optional error set return type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = error{ A, B }; const S = struct { @@ -931,6 +965,8 @@ test "optional error set return type" { } test "optional error set function parameter" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest(a: ?anyerror) !void { try std.testing.expect(a.? == error.OutOfMemory); @@ -960,6 +996,7 @@ test "returning an error union containing a type with no runtime bits" { test "try used in recursive function with inferred error set" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Value = union(enum) { values: []const @This(), @@ -1001,6 +1038,7 @@ test "function called at runtime is properly analyzed for inferred error set" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo() !void { @@ -1024,6 +1062,7 @@ test "generic type constructed from inferred error set of unresolved function" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn write(_: void, bytes: []const u8) !usize { @@ -1039,6 +1078,8 @@ test "generic type constructed from inferred error set of unresolved function" { } test "errorCast to adhoc inferred error set" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { inline fn baz() !i32 { return @errorCast(err()); @@ -1051,6 +1092,8 @@ test "errorCast to adhoc inferred error set" { } test "errorCast from error sets to error unions" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const err_union: Set1!void = @errorCast(error.A); try expectError(error.A, err_union); } @@ -1059,6 +1102,7 @@ test "result location initialization of error union with OPV payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: u0, @@ -1080,6 +1124,7 @@ test "result location initialization of error union with OPV payload" { test "return error union with i65" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(try add(1000, 234) == 1234); } diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 380afd49a5..c62e116a5f 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -73,6 +73,7 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { test "constant expressions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var array: [array_size]u8 = undefined; _ = &array; @@ -142,6 +143,7 @@ test "pointer to type" { test "a type constructed in a global expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var l: List = undefined; l.array[0] = 10; @@ -394,6 +396,7 @@ test "return 0 from function that has u0 return type" { test "statically initialized struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; st_init_str_foo.x += 1; try expect(st_init_str_foo.x == 14); @@ -444,6 +447,7 @@ test "binary math operator in partially inlined function" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var s: [4]u32 = undefined; var b: [16]u8 = undefined; @@ -489,6 +493,7 @@ test "comptime bitwise operators" { test "comptime shlWithOverflow" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0]; var a = ~@as(u64, 0); @@ -501,6 +506,7 @@ test "comptime shlWithOverflow" { test "const ptr to variable data changes at runtime" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(foo_ref.name[0] == 'a'); foo_ref.name = "b"; @@ -522,6 +528,7 @@ test "runtime 128 bit integer division" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u128 = 152313999999999991610955792383; var b: u128 = 10000000000000000000; @@ -542,6 +549,7 @@ test "static eval list init" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(static_vec3.data[2] == 1.0); try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); @@ -713,6 +721,8 @@ fn loopNTimes(comptime n: usize) void { } test "variable inside inline loop that has different types on different iterations" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); } @@ -736,6 +746,7 @@ test "array concatenation of function calls" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = oneItem(3) ++ oneItem(4); try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); @@ -745,6 +756,7 @@ test "array multiplication of function calls" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = oneItem(3) ** scalar(2); try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); @@ -762,6 +774,7 @@ test "array concatenation peer resolves element types - value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [2]u3{ 1, 7 }; var b = [3]u8{ 200, 225, 255 }; @@ -779,6 +792,7 @@ test "array concatenation peer resolves element types - pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [2]u3{ 1, 7 }; var b = [3]u8{ 200, 225, 255 }; @@ -795,6 +809,7 @@ test "array concatenation sets the sentinel - value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [2]u3{ 1, 7 }; var b = [3:69]u8{ 200, 225, 255 }; @@ -813,6 +828,7 @@ test "array concatenation sets the sentinel - value" { test "array concatenation sets the sentinel - pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [2]u3{ 1, 7 }; var b = [3:69]u8{ 200, 225, 255 }; @@ -831,6 +847,7 @@ test "array multiplication sets the sentinel - value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [2:7]u3{ 1, 6 }; _ = &a; @@ -848,6 +865,7 @@ test "array multiplication sets the sentinel - pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = [2:7]u3{ 1, 6 }; const b = &a ** 2; @@ -1070,6 +1088,7 @@ test "comptime break operand passing through runtime condition converted to runt test "comptime break operand passing through runtime switch converted to runtime break" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(runtime: u8) !void { @@ -1090,6 +1109,7 @@ test "comptime break operand passing through runtime switch converted to runtime test "no dependency loop for alignment of self struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1127,6 +1147,7 @@ test "no dependency loop for alignment of self struct" { test "no dependency loop for alignment of self bare union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1164,6 +1185,7 @@ test "no dependency loop for alignment of self bare union" { test "no dependency loop for alignment of self tagged union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1354,6 +1376,7 @@ test "lazy value is resolved as slice operand" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = struct { a: u32 }; var a: [512]u64 = undefined; @@ -1533,6 +1556,7 @@ test "non-optional and optional array elements concatenated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const array = [1]u8{'A'} ++ [1]?u8{null}; var index: usize = 0; @@ -1607,6 +1631,8 @@ test "struct in comptime false branch is not evaluated" { } test "result of nested switch assigned to variable" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var zds: u32 = 0; zds = switch (zds) { 0 => switch (zds) { @@ -1621,6 +1647,8 @@ test "result of nested switch assigned to variable" { } test "inline for loop of functions returning error unions" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const T1 = struct { fn v() error{}!usize { return 1; @@ -1639,6 +1667,8 @@ test "inline for loop of functions returning error unions" { } test "if inside a switch" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var condition = true; var wave_type: u32 = 0; _ = .{ &condition, &wave_type }; diff --git a/test/behavior/export_builtin.zig b/test/behavior/export_builtin.zig index 25b6e2527e..547a9b990a 100644 --- a/test/behavior/export_builtin.zig +++ b/test/behavior/export_builtin.zig @@ -48,6 +48,7 @@ test "exporting using field access" { test "exporting comptime-known value" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho and @@ -67,6 +68,7 @@ test "exporting comptime-known value" { test "exporting comptime var" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho and diff --git a/test/behavior/export_keyword.zig b/test/behavior/export_keyword.zig index a6baf6d1a5..70839959d2 100644 --- a/test/behavior/export_keyword.zig +++ b/test/behavior/export_keyword.zig @@ -9,6 +9,8 @@ const builtin = @import("builtin"); // and generates code const vram = @as([*]volatile u8, @ptrFromInt(0x20000000))[0..0x8000]; export fn writeToVRam() void { + if (builtin.zig_backend == .stage2_riscv64) return; + vram[0] = 'X'; } diff --git a/test/behavior/extern.zig b/test/behavior/extern.zig index a85f300b10..135f5e5648 100644 --- a/test/behavior/extern.zig +++ b/test/behavior/extern.zig @@ -7,6 +7,7 @@ test "anyopaque extern symbol" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" }); const b: *i32 = @alignCast(@ptrCast(a)); @@ -19,6 +20,7 @@ test "function extern symbol" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = @extern(*const fn () callconv(.C) i32, .{ .name = "a_mystery_function" }); try expect(a() == 4567); @@ -32,6 +34,7 @@ test "function extern symbol matches extern decl" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { extern fn another_mystery_function() u32; diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index 51b7fc8cfd..0488d941c4 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/test/behavior/field_parent_ptr.zig @@ -2,6 +2,8 @@ const expect = @import("std").testing.expect; const builtin = @import("builtin"); test "@fieldParentPtr struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const C = struct { a: bool = true, b: f32 = 3.14, @@ -135,6 +137,8 @@ test "@fieldParentPtr struct" { } test "@fieldParentPtr extern struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const C = extern struct { a: bool = true, b: f32 = 3.14, @@ -269,6 +273,7 @@ test "@fieldParentPtr extern struct" { test "@fieldParentPtr extern struct first zero-bit field" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = extern struct { a: u0 = 0, @@ -372,6 +377,7 @@ test "@fieldParentPtr extern struct first zero-bit field" { test "@fieldParentPtr extern struct middle zero-bit field" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = extern struct { a: f32 = 3.14, @@ -475,6 +481,7 @@ test "@fieldParentPtr extern struct middle zero-bit field" { test "@fieldParentPtr extern struct last zero-bit field" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = extern struct { a: f32 = 3.14, @@ -581,6 +588,7 @@ test "@fieldParentPtr unaligned packed struct" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = packed struct { a: bool = true, @@ -719,6 +727,7 @@ test "@fieldParentPtr aligned packed struct" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = packed struct { a: f32 = 3.14, @@ -856,6 +865,7 @@ test "@fieldParentPtr nested packed struct" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { const C = packed struct { @@ -1018,6 +1028,7 @@ test "@fieldParentPtr packed struct first zero-bit field" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = packed struct { a: u0 = 0, @@ -1123,6 +1134,7 @@ test "@fieldParentPtr packed struct middle zero-bit field" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = packed struct { a: f32 = 3.14, @@ -1228,6 +1240,7 @@ test "@fieldParentPtr packed struct last zero-bit field" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = packed struct { a: f32 = 3.14, @@ -1330,6 +1343,8 @@ test "@fieldParentPtr packed struct last zero-bit field" { } test "@fieldParentPtr tagged union" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const C = union(enum) { a: bool, b: f32, @@ -1463,6 +1478,8 @@ test "@fieldParentPtr tagged union" { } test "@fieldParentPtr untagged union" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const C = union { a: bool, b: f32, @@ -1596,6 +1613,8 @@ test "@fieldParentPtr untagged union" { } test "@fieldParentPtr extern union" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const C = extern union { a: bool, b: f32, @@ -1731,6 +1750,7 @@ test "@fieldParentPtr extern union" { test "@fieldParentPtr packed union" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // TODO const C = packed union { @@ -1868,6 +1888,7 @@ test "@fieldParentPtr packed union" { test "@fieldParentPtr tagged union all zero-bit fields" { if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const C = union(enum) { a: u0, diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index a78f9b6f82..2e18b58d3c 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -15,12 +15,15 @@ fn epsForType(comptime T: type) T { test "add f16" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testAdd(f16); try comptime testAdd(f16); } test "add f32/f64" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testAdd(f32); try comptime testAdd(f32); try testAdd(f64); @@ -30,6 +33,7 @@ test "add f32/f64" { test "add f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testAdd(f80); try comptime testAdd(f80); @@ -49,12 +53,15 @@ fn testAdd(comptime T: type) !void { test "sub f16" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSub(f16); try comptime testSub(f16); } test "sub f32/f64" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testSub(f32); try comptime testSub(f32); try testSub(f64); @@ -64,6 +71,7 @@ test "sub f32/f64" { test "sub f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSub(f80); try comptime testSub(f80); @@ -83,12 +91,15 @@ fn testSub(comptime T: type) !void { test "mul f16" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMul(f16); try comptime testMul(f16); } test "mul f32/f64" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testMul(f32); try comptime testMul(f32); try testMul(f64); @@ -98,6 +109,7 @@ test "mul f32/f64" { test "mul f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMul(f80); try comptime testMul(f80); @@ -119,6 +131,7 @@ test "cmp f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCmp(f16); try comptime testCmp(f16); @@ -127,6 +140,7 @@ test "cmp f16" { test "cmp f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCmp(f32); try comptime testCmp(f32); @@ -140,6 +154,7 @@ test "cmp f128" { if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCmp(f128); try comptime testCmp(f128); @@ -213,6 +228,7 @@ test "different sized float comparisons" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testDifferentSizedFloatComparisons(); try comptime testDifferentSizedFloatComparisons(); @@ -261,6 +277,7 @@ test "@sqrt f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSqrt(f16); try comptime testSqrt(f16); @@ -272,6 +289,7 @@ test "@sqrt f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSqrt(f32); try comptime testSqrt(f32); @@ -285,6 +303,7 @@ test "@sqrt f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag == .freebsd) { // TODO https://github.com/ziglang/zig/issues/10875 @@ -371,6 +390,7 @@ test "@sqrt with vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSqrtWithVectors(); try comptime testSqrtWithVectors(); @@ -392,6 +412,7 @@ test "@sin f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSin(f16); try comptime testSin(f16); @@ -403,6 +424,7 @@ test "@sin f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSin(f32); comptime try testSin(f32); @@ -416,6 +438,7 @@ test "@sin f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSin(f80); comptime try testSin(f80); @@ -443,6 +466,7 @@ test "@sin with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSinWithVectors(); try comptime testSinWithVectors(); @@ -464,6 +488,7 @@ test "@cos f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCos(f16); try comptime testCos(f16); @@ -475,6 +500,7 @@ test "@cos f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCos(f32); try comptime testCos(f32); @@ -488,6 +514,7 @@ test "@cos f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCos(f80); try comptime testCos(f80); @@ -515,6 +542,7 @@ test "@cos with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCosWithVectors(); try comptime testCosWithVectors(); @@ -536,6 +564,7 @@ test "@tan f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTan(f16); try comptime testTan(f16); @@ -547,6 +576,7 @@ test "@tan f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTan(f32); try comptime testTan(f32); @@ -560,6 +590,7 @@ test "@tan f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTan(f80); try comptime testTan(f80); @@ -587,6 +618,7 @@ test "@tan with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTanWithVectors(); try comptime testTanWithVectors(); @@ -608,6 +640,7 @@ test "@exp f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp(f16); try comptime testExp(f16); @@ -619,6 +652,7 @@ test "@exp f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp(f32); try comptime testExp(f32); @@ -632,6 +666,7 @@ test "@exp f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp(f80); try comptime testExp(f80); @@ -663,6 +698,7 @@ test "@exp with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExpWithVectors(); try comptime testExpWithVectors(); @@ -684,6 +720,7 @@ test "@exp2 f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp2(f16); try comptime testExp2(f16); @@ -695,6 +732,7 @@ test "@exp2 f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp2(f32); try comptime testExp2(f32); @@ -708,6 +746,7 @@ test "@exp2 f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp2(f80); try comptime testExp2(f80); @@ -734,6 +773,7 @@ test "@exp2 with @vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testExp2WithVectors(); try comptime testExp2WithVectors(); @@ -755,6 +795,7 @@ test "@log f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog(f16); try comptime testLog(f16); @@ -766,6 +807,7 @@ test "@log f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog(f32); try comptime testLog(f32); @@ -779,6 +821,7 @@ test "@log f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog(f80); try comptime testLog(f80); @@ -806,6 +849,7 @@ test "@log with @vectors" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; @@ -824,6 +868,7 @@ test "@log2 f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog2(f16); try comptime testLog2(f16); @@ -835,6 +880,7 @@ test "@log2 f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog2(f32); try comptime testLog2(f32); @@ -848,6 +894,7 @@ test "@log2 f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog2(f80); try comptime testLog2(f80); @@ -873,6 +920,7 @@ test "@log2 with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/13681 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64 and @@ -899,6 +947,7 @@ test "@log10 f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog10(f16); try comptime testLog10(f16); @@ -910,6 +959,7 @@ test "@log10 f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog10(f32); try comptime testLog10(f32); @@ -923,6 +973,7 @@ test "@log10 f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog10(f80); try comptime testLog10(f80); @@ -949,6 +1000,7 @@ test "@log10 with vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testLog10WithVectors(); try comptime testLog10WithVectors(); @@ -969,6 +1021,7 @@ test "@abs f16" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFabs(f16); try comptime testFabs(f16); @@ -978,6 +1031,7 @@ test "@abs f32/f64" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFabs(f32); try comptime testFabs(f32); @@ -992,6 +1046,7 @@ test "@abs f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFabs(f80); try comptime testFabs(f80); @@ -1069,6 +1124,7 @@ test "@abs with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFabsWithVectors(); try comptime testFabsWithVectors(); @@ -1089,6 +1145,7 @@ test "@floor f16" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFloor(f16); try comptime testFloor(f16); @@ -1099,6 +1156,7 @@ test "@floor f32/f64" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFloor(f32); try comptime testFloor(f32); @@ -1113,6 +1171,7 @@ test "@floor f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/12602 @@ -1161,6 +1220,7 @@ test "@floor with vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; @@ -1184,6 +1244,7 @@ test "@ceil f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCeil(f16); try comptime testCeil(f16); @@ -1195,6 +1256,7 @@ test "@ceil f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCeil(f32); try comptime testCeil(f32); @@ -1209,6 +1271,7 @@ test "@ceil f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/12602 @@ -1258,6 +1321,7 @@ test "@ceil with vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; @@ -1281,6 +1345,7 @@ test "@trunc f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) { // https://github.com/ziglang/zig/issues/16846 @@ -1297,6 +1362,7 @@ test "@trunc f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) { // https://github.com/ziglang/zig/issues/16846 @@ -1316,6 +1382,7 @@ test "@trunc f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/12602 @@ -1365,6 +1432,7 @@ test "@trunc with vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; @@ -1389,6 +1457,7 @@ test "neg f16" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag == .freebsd) { // TODO file issue to track this failure @@ -1405,6 +1474,7 @@ test "neg f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testNeg(f32); try comptime testNeg(f32); @@ -1419,6 +1489,7 @@ test "neg f80/f128/c_longdouble" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testNeg(f80); try comptime testNeg(f80); @@ -1525,6 +1596,7 @@ test "comptime fixed-width float zero divided by zero produces NaN" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; inline for (.{ f16, f32, f64, f80, f128 }) |F| { try expect(math.isNan(@as(F, 0) / @as(F, 0))); @@ -1584,6 +1656,7 @@ test "comptime inf >= runtime 1" { test "comptime isNan(nan * 1)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const nan_times_one = comptime std.math.nan(f64) * 1; try std.testing.expect(std.math.isNan(nan_times_one)); @@ -1591,6 +1664,7 @@ test "comptime isNan(nan * 1)" { test "runtime isNan(nan * 1)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const nan_times_one = std.math.nan(f64) * 1; try std.testing.expect(std.math.isNan(nan_times_one)); @@ -1598,6 +1672,7 @@ test "runtime isNan(nan * 1)" { test "comptime isNan(nan * 0)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const nan_times_zero = comptime std.math.nan(f64) * 0; try std.testing.expect(std.math.isNan(nan_times_zero)); @@ -1607,6 +1682,7 @@ test "comptime isNan(nan * 0)" { test "runtime isNan(nan * 0)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const nan_times_zero = std.math.nan(f64) * 0; try std.testing.expect(std.math.isNan(nan_times_zero)); @@ -1616,6 +1692,7 @@ test "runtime isNan(nan * 0)" { test "comptime isNan(inf * 0)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const inf_times_zero = comptime std.math.inf(f64) * 0; try std.testing.expect(std.math.isNan(inf_times_zero)); @@ -1625,6 +1702,7 @@ test "comptime isNan(inf * 0)" { test "runtime isNan(inf * 0)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const inf_times_zero = std.math.inf(f64) * 0; try std.testing.expect(std.math.isNan(inf_times_zero)); diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index ab7aca6ed6..b6eafeefc1 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -71,6 +71,7 @@ fn outer(y: u32) *const fn (u32) u32 { test "return inner function which references comptime variable of outer function" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const func = outer(10); try expect(func(3) == 7); @@ -80,6 +81,7 @@ test "discard the result of a function that returns a struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() void { @@ -104,6 +106,7 @@ test "inline function call that calls optional function pointer, return pointer if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { field: u32, @@ -181,12 +184,14 @@ test "function with complex callconv and return type expressions" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(fComplexCallconvRet(3).x == 9); } test "pass by non-copying value" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); } @@ -202,6 +207,7 @@ fn addPointCoords(pt: Point) i32 { test "pass by non-copying value through var arg" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3); } @@ -213,6 +219,7 @@ fn addPointCoordsVar(pt: anytype) !i32 { test "pass by non-copying value as method" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var pt = Point2{ .x = 1, .y = 2 }; try expect(pt.addPointCoords() == 3); @@ -229,6 +236,7 @@ const Point2 = struct { test "pass by non-copying value as method, which is generic" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var pt = Point3{ .x = 1, .y = 2 }; try expect(pt.addPointCoords(i32) == 3); @@ -257,6 +265,7 @@ test "implicit cast fn call result to optional in field result" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -283,6 +292,7 @@ test "implicit cast fn call result to optional in field result" { test "void parameters" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try voidFun(1, void{}, 2, {}); } @@ -346,6 +356,7 @@ test "function call with anon list literal" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -366,6 +377,7 @@ test "function call with anon list literal - 2D" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -402,6 +414,8 @@ test "ability to give comptime types and non comptime types to same parameter" { } test "function with inferred error set but returning no error" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn foo() !void {} }; @@ -412,6 +426,7 @@ test "function with inferred error set but returning no error" { test "import passed byref to function in return type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn get() @import("std").ArrayListUnmanaged(i32) { @@ -429,6 +444,7 @@ test "implicit cast function to function ptr" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S1 = struct { export fn someFunctionThatReturnsAValue() c_int { @@ -449,6 +465,7 @@ test "implicit cast function to function ptr" { test "method call with optional and error union first param" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: i32 = 1234, @@ -468,6 +485,7 @@ test "method call with optional and error union first param" { test "method call with optional pointer first param" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: i32 = 1234, @@ -487,6 +505,7 @@ test "using @ptrCast on function pointers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const A = struct { data: [4]u8 }; @@ -524,6 +543,7 @@ test "function returns function returning type" { test "peer type resolution of inferred error set with non-void payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn openDataFile(mode: enum { read, write }) !u32 { @@ -566,6 +586,8 @@ test "lazy values passed to anytype parameter" { } test "pass and return comptime-only types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn returnNull(comptime x: @Type(.Null)) @Type(.Null) { return x; diff --git a/test/behavior/fn_delegation.zig b/test/behavior/fn_delegation.zig index 95dbfeb4b2..6a3d46c15d 100644 --- a/test/behavior/fn_delegation.zig +++ b/test/behavior/fn_delegation.zig @@ -34,6 +34,7 @@ fn custom(comptime T: type, comptime num: u64) fn (T) u64 { test "fn delegation" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const foo = Foo{}; try expect(foo.one() == 11); diff --git a/test/behavior/for.zig b/test/behavior/for.zig index 7614fd4683..1eac03ec79 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -69,6 +69,7 @@ test "basic for loop" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; @@ -112,6 +113,7 @@ test "for with null and T peer types and inferred result location type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(slice: []const u8) !void { @@ -132,6 +134,7 @@ test "for with null and T peer types and inferred result location type" { test "2 break statements and an else" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry(t: bool, f: bool) !void { @@ -153,6 +156,7 @@ test "for loop with pointer elem var" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const source = "abcdefg"; var target: [source.len]u8 = undefined; @@ -179,6 +183,7 @@ fn mangleString(s: []u8) void { test "for copies its payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -198,6 +203,7 @@ test "for on slice with allowzero ptr" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(slice: []const u8) !void { @@ -213,6 +219,7 @@ test "for on slice with allowzero ptr" { test "else continue outer for" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var i: usize = 6; var buf: [5]u8 = undefined; @@ -226,6 +233,7 @@ test "else continue outer for" { test "for loop with else branch" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var x = [_]u32{ 1, 2 }; @@ -275,6 +283,7 @@ test "two counters" { test "1-based counter and ptr to array" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var ok: usize = 0; @@ -308,6 +317,7 @@ test "slice and two counters, one is offset and one is runtime" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const slice: []const u8 = "blah"; var start: usize = 0; @@ -337,6 +347,7 @@ test "two slices, one captured by-ref" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [10]u8 = undefined; const slice1: []const u8 = "blah"; @@ -356,6 +367,7 @@ test "raw pointer and slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [10]u8 = undefined; const slice: []const u8 = "blah"; @@ -375,6 +387,7 @@ test "raw pointer and counter" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [10]u8 = undefined; const ptr: [*]u8 = &buf; @@ -393,6 +406,7 @@ test "inline for with slice as the comptime-known" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const comptime_slice = "hello"; var runtime_i: usize = 3; @@ -424,6 +438,7 @@ test "inline for with counter as the comptime-known" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var runtime_slice = "hello"; var runtime_i: usize = 3; @@ -456,6 +471,7 @@ test "inline for on tuple pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { u32, u32, u32 }; var s: S = .{ 100, 200, 300 }; @@ -471,6 +487,7 @@ test "ref counter that starts at zero" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; for ([_]usize{ 0, 1, 2 }, 0..) |i, j| { try expectEqual(i, j); @@ -486,6 +503,7 @@ test "inferred alloc ptr of for loop" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var cond = false; diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 9786ea5d06..7ed75f0ead 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -19,6 +19,7 @@ fn checkSize(comptime T: type) usize { test "simple generic fn" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(max(i32, 3, -1) == 3); try expect(max(u8, 1, 100) == 100); @@ -55,6 +56,7 @@ test "fn with comptime args" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(gimmeTheBigOne(1234, 5678) == 5678); try expect(shouldCallSameInstance(34, 12) == 34); @@ -65,6 +67,7 @@ test "anytype params" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(max_i32(12, 34) == 34); try expect(max_f64(1.2, 3.4) == 3.4); @@ -89,6 +92,7 @@ fn max_f64(a: f64, b: f64) f64 { test "type constructed by comptime function call" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var l: SimpleList(10) = undefined; l.array[0] = 10; @@ -113,6 +117,7 @@ test "function with return type type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var list: List(i32) = undefined; var list2: List(i32) = undefined; @@ -154,6 +159,7 @@ test "generic fn with implicit cast" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(getFirstByte(u8, &[_]u8{13}) == 13); try expect(getFirstByte(u16, &[_]u16{ @@ -172,6 +178,7 @@ test "generic fn keeps non-generic parameter types" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = 128; @@ -280,6 +287,7 @@ test "generic function instantiation turns into comptime call" { test "generic function with void and comptime parameter" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: i32 }; const namespace = struct { @@ -296,6 +304,7 @@ test "generic function with void and comptime parameter" { test "anonymous struct return type referencing comptime parameter" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { pub fn extraData(comptime T: type, index: usize) struct { data: T, end: usize } { @@ -314,6 +323,7 @@ test "generic function instantiation non-duplicates" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag == .wasi) return error.SkipZigTest; const S = struct { @@ -385,6 +395,7 @@ test "extern function used as generic parameter" { test "generic struct as parameter type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(comptime Int: type, thing: struct { int: Int }) !void { @@ -399,6 +410,8 @@ test "generic struct as parameter type" { } test "slice as parameter type" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn internComptimeString(comptime str: []const u8) *const []const u8 { return &struct { @@ -423,6 +436,7 @@ test "null sentinel pointer passed as generic argument" { test "generic function passed as comptime argument" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doMath(comptime f: fn (type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void { @@ -435,6 +449,7 @@ test "generic function passed as comptime argument" { test "return type of generic function is function pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn b(comptime T: type) ?*const fn () error{}!T { @@ -447,6 +462,7 @@ test "return type of generic function is function pointer" { test "coerced function body has inequal value with its uncoerced body" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const A = B(i32, c); @@ -496,6 +512,7 @@ test "union in struct captures argument" { test "function argument tuple used as struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn DeleagateWithContext(comptime Function: type) type { @@ -530,6 +547,7 @@ test "call generic function with from function called by the generic function" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) return error.SkipZigTest; @@ -572,6 +590,7 @@ fn StructCapture(comptime T: type) type { test "call generic function that uses capture from function declaration's scope" { if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = StructCapture(f64); const s = S.foo(123); diff --git a/test/behavior/globals.zig b/test/behavior/globals.zig index 89dc20c5c7..0c988450c0 100644 --- a/test/behavior/globals.zig +++ b/test/behavior/globals.zig @@ -7,6 +7,7 @@ test "store to global array" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(pos[1] == 0.0); pos = [2]f32{ 0.0, 1.0 }; @@ -18,6 +19,7 @@ test "store to global vector" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(vpos[1] == 0.0); vpos = @Vector(2, f32){ 0.0, 1.0 }; @@ -28,6 +30,7 @@ test "slices pointing at the same address as global array." { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const a = [_]u8{ 1, 2, 3 }; diff --git a/test/behavior/hasdecl.zig b/test/behavior/hasdecl.zig index 7eeba80f3e..71f9200b27 100644 --- a/test/behavior/hasdecl.zig +++ b/test/behavior/hasdecl.zig @@ -12,6 +12,8 @@ const Bar = struct { }; test "@hasDecl" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(@hasDecl(Foo, "public_thing")); try expect(!@hasDecl(Foo, "private_thing")); try expect(!@hasDecl(Foo, "no_thing")); @@ -22,6 +24,8 @@ test "@hasDecl" { } test "@hasDecl using a sliced string literal" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(@hasDecl(@This(), "std") == true); try expect(@hasDecl(@This(), "std"[0..0]) == false); try expect(@hasDecl(@This(), "std"[0..1]) == false); diff --git a/test/behavior/if.zig b/test/behavior/if.zig index 69ad917e6a..8cb923dd43 100644 --- a/test/behavior/if.zig +++ b/test/behavior/if.zig @@ -45,6 +45,7 @@ var global_with_err: anyerror!u32 = error.SomeError; test "unwrap mutable global var" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (global_with_val) |v| { try expect(v == 0); @@ -82,6 +83,7 @@ test "const result loc, runtime if cond, else unreachable" { test "if copies its payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -118,6 +120,7 @@ test "if peer expressions inferred optional type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var self: []const u8 = "abcdef"; var index: usize = 0; @@ -136,6 +139,7 @@ test "if-else expression with runtime condition result location is inferred opti if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = struct { b: u64, c: u64 }; var d: bool = true; @@ -145,6 +149,8 @@ test "if-else expression with runtime condition result location is inferred opti } test "result location with inferred type ends up being pointer to comptime_int" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var a: ?u32 = 1234; var b: u32 = 2000; _ = .{ &a, &b }; @@ -190,6 +196,8 @@ test "if value shouldn't be load-elided if used later (structs)" { } test "if value shouldn't be load-elided if used later (optionals)" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var a: ?i32 = 1; var b: ?i32 = 1; diff --git a/test/behavior/import.zig b/test/behavior/import.zig index c2bb39983d..befaea9cae 100644 --- a/test/behavior/import.zig +++ b/test/behavior/import.zig @@ -6,18 +6,21 @@ const a_namespace = @import("import/a_namespace.zig"); test "call fn via namespace lookup" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@as(i32, 1234) == a_namespace.foo()); } test "importing the same thing gives the same import" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@import("std") == @import("std")); } test "import in non-toplevel scope" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { usingnamespace @import("import/a_namespace.zig"); @@ -27,6 +30,7 @@ test "import in non-toplevel scope" { test "import empty file" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; _ = @import("import/empty.zig"); } diff --git a/test/behavior/import_c_keywords.zig b/test/behavior/import_c_keywords.zig index 3ef952c9e6..9029dca31d 100644 --- a/test/behavior/import_c_keywords.zig +++ b/test/behavior/import_c_keywords.zig @@ -33,6 +33,7 @@ test "import c keywords" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try std.testing.expect(int == .c_keyword_variable); try std.testing.expect(long == .c_keyword_variable); diff --git a/test/behavior/incomplete_struct_param_tld.zig b/test/behavior/incomplete_struct_param_tld.zig index 4edf974dab..485156de04 100644 --- a/test/behavior/incomplete_struct_param_tld.zig +++ b/test/behavior/incomplete_struct_param_tld.zig @@ -23,6 +23,7 @@ fn foo(a: A) i32 { test "incomplete struct param top level declaration" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = A{ .b = B{ diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig index 59dc7096b9..444697b091 100644 --- a/test/behavior/inline_switch.zig +++ b/test/behavior/inline_switch.zig @@ -5,6 +5,7 @@ const builtin = @import("builtin"); test "inline scalar prongs" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: usize = 0; switch (x) { @@ -20,6 +21,7 @@ test "inline scalar prongs" { test "inline prong ranges" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: usize = 0; _ = &x; @@ -35,6 +37,7 @@ const E = enum { a, b, c, d }; test "inline switch enums" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: E = .a; _ = &x; @@ -49,6 +52,7 @@ test "inline switch unions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: U = .a; _ = &x; @@ -75,6 +79,7 @@ test "inline switch unions" { test "inline else bool" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a = true; _ = &a; @@ -87,6 +92,7 @@ test "inline else bool" { test "inline else error" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Err = error{ a, b, c }; var a = Err.a; @@ -100,6 +106,7 @@ test "inline else error" { test "inline else enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; var a: E2 = .a; @@ -113,6 +120,7 @@ test "inline else enum" { test "inline else int with gaps" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u8 = 0; _ = &a; @@ -131,6 +139,7 @@ test "inline else int with gaps" { test "inline else int all values" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u2 = 0; _ = &a; diff --git a/test/behavior/int128.zig b/test/behavior/int128.zig index 6d7b54ea31..544b38fca6 100644 --- a/test/behavior/int128.zig +++ b/test/behavior/int128.zig @@ -9,6 +9,7 @@ test "uint128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buff: u128 = maxInt(u128); try expect(buff == maxInt(u128)); @@ -28,6 +29,7 @@ test "undefined 128 bit int" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @setRuntimeSafety(true); @@ -47,6 +49,7 @@ test "int128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buff: i128 = -1; try expect(buff < 0 and (buff + 1) == 0); @@ -70,6 +73,7 @@ test "truncate int128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var buff: u128 = maxInt(u128); @@ -93,6 +97,7 @@ test "shift int128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const types = .{ u128, i128 }; inline for (types) |t| { diff --git a/test/behavior/int_comparison_elision.zig b/test/behavior/int_comparison_elision.zig index 28102ef295..2e25cef8f8 100644 --- a/test/behavior/int_comparison_elision.zig +++ b/test/behavior/int_comparison_elision.zig @@ -4,6 +4,8 @@ const maxInt = std.math.maxInt; const builtin = @import("builtin"); test "int comparison elision" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + testIntEdges(u0); testIntEdges(i0); testIntEdges(u1); diff --git a/test/behavior/int_div.zig b/test/behavior/int_div.zig index c3c32f1e9a..e9aac82240 100644 --- a/test/behavior/int_div.zig +++ b/test/behavior/int_div.zig @@ -6,6 +6,7 @@ test "integer division" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testDivision(); try comptime testDivision(); @@ -97,6 +98,7 @@ test "large integer division" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var numerator: u256 = 99999999999999999997315645440; diff --git a/test/behavior/ir_block_deps.zig b/test/behavior/ir_block_deps.zig index a46ad2d8a8..e3bb57cf89 100644 --- a/test/behavior/ir_block_deps.zig +++ b/test/behavior/ir_block_deps.zig @@ -21,6 +21,7 @@ test "ir block deps" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect((foo(1) catch unreachable) == 0); try expect((foo(2) catch unreachable) == 0); diff --git a/test/behavior/lower_strlit_to_vector.zig b/test/behavior/lower_strlit_to_vector.zig index 948d708aa7..79315e7a53 100644 --- a/test/behavior/lower_strlit_to_vector.zig +++ b/test/behavior/lower_strlit_to_vector.zig @@ -6,6 +6,7 @@ test "strlit to vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const strlit = "0123456789abcdef0123456789ABCDEF"; const vec_from_strlit: @Vector(32, u8) = strlit.*; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index efc698c128..eaef26b804 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -12,6 +12,7 @@ const math = std.math; test "assignment operators" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var i: u32 = 0; i += 5; @@ -64,6 +65,7 @@ test "@clz" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testClz(); try comptime testClz(); @@ -82,6 +84,7 @@ test "@clz big ints" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testClzBigInts(); try comptime testClzBigInts(); @@ -103,6 +106,7 @@ test "@clz vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testClzVectors(); try comptime testClzVectors(); @@ -146,6 +150,7 @@ test "@ctz" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCtz(); try comptime testCtz(); @@ -169,6 +174,7 @@ test "@ctz 128-bit integers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCtz128(); try comptime testCtz128(); @@ -187,6 +193,7 @@ test "@ctz vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // This regressed with LLVM 14: @@ -229,6 +236,7 @@ test "float equality" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const x: f64 = 0.012; const y: f64 = x + 1.0; @@ -343,6 +351,8 @@ test "comptime_int multi-limb partial shift right" { } test "xor" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try test_xor(); try comptime test_xor(); } @@ -385,6 +395,8 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int } test "binary not" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(comptime x: { break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101; }); @@ -407,6 +419,7 @@ test "binary not 128-bit" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(comptime x: { break :x ~@as(u128, 0x55555555_55555555_55555555_55555555) == 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa; @@ -430,6 +443,7 @@ test "division" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) { // https://github.com/ziglang/zig/issues/16846 @@ -518,6 +532,7 @@ test "division half-precision floats" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testDivisionFP16(); try comptime testDivisionFP16(); @@ -554,6 +569,8 @@ fn mod(comptime T: type, a: T, b: T) T { } test "unsigned wrapping" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testUnsignedWrappingEval(maxInt(u32)); try comptime testUnsignedWrappingEval(maxInt(u32)); } @@ -565,6 +582,8 @@ fn testUnsignedWrappingEval(x: u32) !void { } test "signed wrapping" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testSignedWrappingEval(maxInt(i32)); try comptime testSignedWrappingEval(maxInt(i32)); } @@ -576,6 +595,8 @@ fn testSignedWrappingEval(x: i32) !void { } test "signed negation wrapping" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testSignedNegationWrappingEval(minInt(i16)); try comptime testSignedNegationWrappingEval(minInt(i16)); } @@ -586,6 +607,8 @@ fn testSignedNegationWrappingEval(x: i16) !void { } test "unsigned negation wrapping" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testUnsignedNegationWrappingEval(1); try comptime testUnsignedNegationWrappingEval(1); } @@ -598,6 +621,7 @@ fn testUnsignedNegationWrappingEval(x: u16) !void { test "negation wrapping" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expectEqual(@as(u1, 1), negateWrap(u1, 1)); } @@ -611,6 +635,7 @@ fn negateWrap(comptime T: type, x: T) T { test "unsigned 64-bit division" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) { // https://github.com/ziglang/zig/issues/16846 @@ -644,6 +669,8 @@ test "bit shift a u1" { } test "truncating shift right" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testShrTrunc(maxInt(u16)); try comptime testShrTrunc(maxInt(u16)); } @@ -658,6 +685,7 @@ test "f128" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try test_f128(); try comptime test_f128(); @@ -689,6 +717,7 @@ test "128-bit multiplication" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var a: i128 = 3; @@ -715,6 +744,7 @@ test "@addWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var a: u8 = 250; @@ -765,6 +795,7 @@ test "@addWithOverflow" { test "small int addition" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u2 = 0; try expect(x == 0); @@ -786,6 +817,7 @@ test "small int addition" { test "basic @mulWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var a: u8 = 86; @@ -818,6 +850,7 @@ test "basic @mulWithOverflow" { test "extensive @mulWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var a: u5 = 3; @@ -989,6 +1022,8 @@ test "extensive @mulWithOverflow" { } test "@mulWithOverflow bitsize > 32" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // aarch64 fails on a release build of the compiler. if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -1056,6 +1091,7 @@ test "@mulWithOverflow u256" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { const const_lhs: u256 = 8035709466408580321693645878924206181189; @@ -1091,6 +1127,7 @@ test "@subWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var a: u8 = 1; @@ -1143,6 +1180,7 @@ test "@shlWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var a: u4 = 2; @@ -1250,6 +1288,7 @@ test "quad hex float literal parsing accurate" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a: f128 = 0x1.1111222233334444555566667777p+0; @@ -1345,6 +1384,8 @@ test "quad hex float literal parsing accurate" { } test "truncating shift left" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testShlTrunc(maxInt(u16)); try comptime testShlTrunc(maxInt(u16)); } @@ -1354,6 +1395,8 @@ fn testShlTrunc(x: u16) !void { } test "exact shift left" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testShlExact(0b00110101); try comptime testShlExact(0b00110101); @@ -1365,6 +1408,8 @@ fn testShlExact(x: u8) !void { } test "exact shift right" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try testShrExact(0b10110100); try comptime testShrExact(0b10110100); } @@ -1374,6 +1419,8 @@ fn testShrExact(x: u8) !void { } test "shift left/right on u0 operand" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var x: u0 = 0; @@ -1408,6 +1455,7 @@ test "remainder division" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { // https://github.com/ziglang/zig/issues/12602 @@ -1446,6 +1494,7 @@ test "float remainder division using @rem" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime frem(f16); try comptime frem(f32); @@ -1489,6 +1538,7 @@ test "float modulo division using @mod" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime fmod(f16); try comptime fmod(f32); @@ -1531,6 +1581,7 @@ test "@round f16" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f16, 12.0); try comptime testRound(f16, 12.0); @@ -1542,6 +1593,7 @@ test "@round f32/f64" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f64, 12.0); try comptime testRound(f64, 12.0); @@ -1561,6 +1613,7 @@ test "@round f80" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f80, 12.0); try comptime testRound(f80, 12.0); @@ -1573,6 +1626,7 @@ test "@round f128" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testRound(f128, 12.0); try comptime testRound(f128, 12.0); @@ -1590,6 +1644,7 @@ test "vector integer addition" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1612,6 +1667,7 @@ test "NaN comparison" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testNanEqNan(f16); try testNanEqNan(f32); @@ -1629,6 +1685,7 @@ test "NaN comparison f80" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testNanEqNan(f80); try comptime testNanEqNan(f80); @@ -1651,6 +1708,7 @@ test "vector comparison" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx2)) return error.SkipZigTest; @@ -1683,6 +1741,7 @@ test "signed zeros are represented properly" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1712,6 +1771,7 @@ test "absFloat" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testAbsFloat(); try comptime testAbsFloat(); @@ -1745,6 +1805,7 @@ test "@clz works on both vector and scalar inputs" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u32 = 0x1; _ = &x; diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index a6a2e3b8e8..d08bc82828 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -9,6 +9,7 @@ test "@max" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -31,6 +32,7 @@ test "@max on vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; @@ -63,6 +65,7 @@ test "@min" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -85,6 +88,7 @@ test "@min for vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; @@ -120,6 +124,7 @@ test "@min/max for floats" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(comptime T: type) !void { @@ -167,6 +172,7 @@ test "@min/@max more than two vector arguments" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const x: @Vector(2, u32) = .{ 3, 2 }; const y: @Vector(2, u32) = .{ 4, 1 }; @@ -198,6 +204,7 @@ test "@min/@max notices vector bounds" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: @Vector(2, u16) = .{ 140, 40 }; const y: @Vector(2, u64) = .{ 5, 100 }; @@ -251,6 +258,7 @@ test "@min/@max notices bounds from vector types" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: @Vector(2, u16) = .{ 30, 67 }; var y: @Vector(2, u32) = .{ 20, 500 }; @@ -271,6 +279,7 @@ test "@min/@max notices bounds from types when comptime-known value is undef" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u32 = 1_000_000; _ = &x; @@ -291,6 +300,7 @@ test "@min/@max notices bounds from vector types when element of comptime-known if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx)) return error.SkipZigTest; diff --git a/test/behavior/member_func.zig b/test/behavior/member_func.zig index bb1e1e1769..1563ad7a4a 100644 --- a/test/behavior/member_func.zig +++ b/test/behavior/member_func.zig @@ -31,6 +31,7 @@ test "standard field calls" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(HasFuncs.one(0) == 1); try expect(HasFuncs.two(0) == 2); @@ -75,6 +76,7 @@ test "@field field calls" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@field(HasFuncs, "one")(0) == 1); try expect(@field(HasFuncs, "two")(0) == 2); diff --git a/test/behavior/memcpy.zig b/test/behavior/memcpy.zig index fa9203713d..a571b1e2f7 100644 --- a/test/behavior/memcpy.zig +++ b/test/behavior/memcpy.zig @@ -7,6 +7,7 @@ test "memcpy and memset intrinsics" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMemcpyMemset(); try comptime testMemcpyMemset(); @@ -28,6 +29,7 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMemcpyBothSinglePtrArrayOneIsNullTerminated(); try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated(); @@ -48,6 +50,7 @@ test "@memcpy dest many pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMemcpyDestManyPtr(); try comptime testMemcpyDestManyPtr(); @@ -70,6 +73,7 @@ test "@memcpy slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMemcpySlice(); try comptime testMemcpySlice(); diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 69f890e146..185c6fafe1 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -7,6 +7,7 @@ test "@memset on array pointers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMemsetArray(); try comptime testMemsetArray(); @@ -36,6 +37,7 @@ test "@memset on slices" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testMemsetSlice(); try comptime testMemsetSlice(); @@ -71,6 +73,7 @@ test "memset with bool element" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [5]bool = undefined; @memset(&buf, true); @@ -83,6 +86,7 @@ test "memset with 1-byte struct element" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: bool }; var buf: [5]S = undefined; @@ -96,6 +100,7 @@ test "memset with 1-byte array element" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = [1]bool; var buf: [5]A = undefined; @@ -109,6 +114,7 @@ test "memset with large array element, runtime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; @@ -127,6 +133,7 @@ test "memset with large array element, comptime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; @@ -144,6 +151,7 @@ test "@memset provides result type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: u32 }; @@ -162,6 +170,7 @@ test "zero keys with @memset" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Keys = struct { up: bool, diff --git a/test/behavior/merge_error_sets.zig b/test/behavior/merge_error_sets.zig index 492cb27699..b1f7f69d56 100644 --- a/test/behavior/merge_error_sets.zig +++ b/test/behavior/merge_error_sets.zig @@ -13,6 +13,7 @@ fn foo() C!void { test "merge error sets" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (foo()) { @panic("unexpected"); diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 000f3fbd95..7b45cc9b72 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -6,6 +6,8 @@ const no_x86_64_hardware_fma_support = builtin.zig_backend == .stage2_x86_64 and !std.Target.x86.featureSetHas(builtin.cpu.features, .fma); test "@mulAdd" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -37,6 +39,7 @@ test "@mulAdd f16" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd16(); try testMulAdd16(); @@ -57,6 +60,7 @@ test "@mulAdd f80" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd80(); try testMulAdd80(); @@ -77,6 +81,7 @@ test "@mulAdd f128" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testMulAdd128(); try testMulAdd128(); @@ -109,6 +114,7 @@ test "vector f16" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector16(); try vector16(); @@ -129,6 +135,7 @@ fn vector32() !void { test "vector f32" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -153,6 +160,7 @@ fn vector64() !void { test "vector f64" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (no_x86_64_hardware_fma_support) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -182,6 +190,7 @@ test "vector f80" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector80(); try vector80(); @@ -208,6 +217,7 @@ test "vector f128" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime vector128(); try vector128(); diff --git a/test/behavior/multiple_externs_with_conflicting_types.zig b/test/behavior/multiple_externs_with_conflicting_types.zig index bd9735aee9..ac13e2bf34 100644 --- a/test/behavior/multiple_externs_with_conflicting_types.zig +++ b/test/behavior/multiple_externs_with_conflicting_types.zig @@ -16,6 +16,7 @@ test "call extern function defined with conflicting type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @import("conflicting_externs/a.zig").issue529(null); issue529(null); diff --git a/test/behavior/namespace_depends_on_compile_var.zig b/test/behavior/namespace_depends_on_compile_var.zig index a115f557ab..cd8e42f20d 100644 --- a/test/behavior/namespace_depends_on_compile_var.zig +++ b/test/behavior/namespace_depends_on_compile_var.zig @@ -4,6 +4,7 @@ const expect = std.testing.expect; test "namespace depends on compile var" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (some_namespace.a_bool) { try expect(some_namespace.a_bool); diff --git a/test/behavior/nan.zig b/test/behavior/nan.zig index fc5ce4d0f9..e177afa9d0 100644 --- a/test/behavior/nan.zig +++ b/test/behavior/nan.zig @@ -26,6 +26,7 @@ test "nan memory equality" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // signaled try testing.expect(mem.eql(u8, mem.asBytes(&snan_u16), mem.asBytes(&snan_f16))); diff --git a/test/behavior/null.zig b/test/behavior/null.zig index ffebff6d83..323f47c896 100644 --- a/test/behavior/null.zig +++ b/test/behavior/null.zig @@ -32,6 +32,7 @@ test "test maybe object and get a pointer to the inner value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var maybe_bool: ?bool = true; @@ -52,6 +53,7 @@ test "maybe return" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try maybeReturnImpl(); try comptime maybeReturnImpl(); @@ -71,6 +73,7 @@ fn foo(x: ?i32) ?bool { test "test null runtime" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testTestNullRuntime(null); } @@ -82,6 +85,7 @@ fn testTestNullRuntime(x: ?i32) !void { test "optional void" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try optionalVoidImpl(); try comptime optionalVoidImpl(); @@ -105,6 +109,7 @@ const Empty = struct {}; test "optional struct{}" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; _ = try optionalEmptyStructImpl(); _ = try comptime optionalEmptyStructImpl(); @@ -130,6 +135,7 @@ test "null with default unwrap" { test "optional pointer to 0 bit type null value at runtime" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const EmptyStruct = struct {}; var x: ?*EmptyStruct = null; @@ -141,6 +147,7 @@ test "if var maybe pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(shouldBeAPlus1(Particle{ .a = 14, @@ -184,6 +191,7 @@ test "unwrap optional which is field of global var" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; struct_with_optional.field = null; if (struct_with_optional.field) |payload| { diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index f370f324ea..02c329a7d5 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -9,6 +9,7 @@ const expectEqualStrings = std.testing.expectEqualStrings; test "passing an optional integer as a parameter" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() bool { @@ -28,6 +29,7 @@ pub const EmptyStruct = struct {}; test "optional pointer to size zero struct" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var e = EmptyStruct{}; const o: ?*EmptyStruct = &e; @@ -58,6 +60,7 @@ fn testNullPtrsEql() !void { test "optional with zero-bit type" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(comptime ZeroBit: type, comptime zero_bit: ZeroBit) !void { @@ -110,6 +113,7 @@ test "address of unwrap optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Foo = struct { @@ -131,6 +135,7 @@ test "nested optional field in struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S2 = struct { y: u8, @@ -149,6 +154,7 @@ test "equality compare optionals and non-optionals" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -206,6 +212,7 @@ test "equality compare optionals and non-optionals" { test "compare optionals with modified payloads" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var lhs: ?bool = false; const lhs_payload = &lhs.?; @@ -233,6 +240,7 @@ test "compare optionals with modified payloads" { test "unwrap function call with optional pointer return value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -254,6 +262,7 @@ test "unwrap function call with optional pointer return value" { test "nested orelse" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -280,6 +289,7 @@ test "nested orelse" { test "self-referential struct through a slice of optional" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Node = struct { @@ -316,6 +326,7 @@ test "coerce an anon struct literal to optional struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Struct = struct { @@ -335,6 +346,7 @@ test "0-bit child type coerced to optional return ptr result location" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -360,6 +372,7 @@ test "0-bit child type coerced to optional return ptr result location" { test "0-bit child type coerced to optional" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -387,6 +400,7 @@ test "array of optional unaligned types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Enum = enum { one, two, three }; @@ -423,6 +437,7 @@ test "optional pointer to zero bit optional payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const B = struct { fn foo(_: *@This()) void {} @@ -442,6 +457,7 @@ test "optional pointer to zero bit error union payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const B = struct { fn foo(_: *@This()) void {} @@ -475,6 +491,7 @@ const NoReturn = struct { test "optional of noreturn used with if" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; if (NoReturn.loop()) |_| { @@ -486,6 +503,7 @@ test "optional of noreturn used with if" { test "optional of noreturn used with orelse" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; NoReturn.a = 64; const val = NoReturn.testOrelse(); @@ -505,6 +523,7 @@ test "alignment of wrapping an optional payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const I = extern struct { x: i128 }; @@ -522,6 +541,7 @@ test "Optional slice size is optimized" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@sizeOf(?[]u8) == @sizeOf([]u8)); var a: ?[]const u8 = null; @@ -535,6 +555,7 @@ test "Optional slice passed to function" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(a: ?[]const u8) !void { @@ -551,6 +572,7 @@ test "Optional slice passed to function" { test "peer type resolution in nested if expressions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Thing = struct { n: i32 }; var a = false; @@ -578,6 +600,7 @@ test "cast slice to const slice nested in error union and optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn inner() !?[]u8 { @@ -591,6 +614,8 @@ test "cast slice to const slice nested in error union and optional" { } test "variable of optional of noreturn" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var null_opv: ?noreturn = null; _ = &null_opv; try std.testing.expectEqual(@as(?noreturn, null), null_opv); @@ -600,6 +625,7 @@ test "copied optional doesn't alias source" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var opt_x: ?[3]f32 = [_]f32{0.0} ** 3; @@ -614,6 +640,7 @@ test "result location initialization of optional with OPV payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: u0, diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index b194f7ac9e..4870cd5984 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -238,6 +238,7 @@ test "regular in irregular packed struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Irregular = packed struct { bar: Regular = Regular{}, @@ -258,6 +259,7 @@ test "nested packed struct unaligned" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet const S1 = packed struct { @@ -330,6 +332,7 @@ test "byte-aligned field pointer offsets" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const A = packed struct { @@ -432,6 +435,7 @@ test "nested packed struct field pointers" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet const S2 = packed struct { @@ -469,6 +473,7 @@ test "load pointer from packed struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = struct { index: u16, @@ -489,6 +494,7 @@ test "@intFromPtr on a packed struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (native_endian != .little) return error.SkipZigTest; const S = struct { @@ -512,6 +518,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet const S1 = packed struct { @@ -618,6 +625,8 @@ test "@intFromPtr on a packed struct field unaligned and nested" { } test "packed struct fields modification" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // Originally reported at https://github.com/ziglang/zig/issues/16615 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -646,6 +655,7 @@ test "optional pointer in packed struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = packed struct { ptr: ?*const u8 }; var n: u8 = 0; @@ -661,6 +671,7 @@ test "nested packed struct field access test" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Vec2 = packed struct { x: f32, @@ -777,6 +788,7 @@ test "nested packed struct field access test" { test "nested packed struct at non-zero offset" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Pair = packed struct(u24) { a: u16 = 0, @@ -810,6 +822,7 @@ test "nested packed struct at non-zero offset 2" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Pair = packed struct(u40) { @@ -890,6 +903,7 @@ test "packed struct passed to callconv(.C) function" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Packed = packed struct { @@ -938,6 +952,7 @@ test "packed struct initialized in bitcast" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = packed struct { val: u8 }; var val: u8 = 123; @@ -951,6 +966,7 @@ test "pointer to container level packed struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct(u32) { test_bit: bool, @@ -975,6 +991,7 @@ test "store undefined to packed result location" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u4 = 0; _ = &x; @@ -995,6 +1012,8 @@ test "bitcast back and forth" { } test "field access of packed struct smaller than its abi size inside struct initialized with rls" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // Originally reported at https://github.com/ziglang/zig/issues/14200 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1013,6 +1032,8 @@ test "field access of packed struct smaller than its abi size inside struct init } test "modify nested packed struct aligned field" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // Originally reported at https://github.com/ziglang/zig/issues/14632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -1043,6 +1064,8 @@ test "modify nested packed struct aligned field" { } test "assigning packed struct inside another packed struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // Originally reported at https://github.com/ziglang/zig/issues/9674 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1077,6 +1100,7 @@ test "packed struct used as part of anon decl name" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct { a: u0 = 0 }; var a: u8 = 0; @@ -1099,6 +1123,8 @@ test "packed struct acts as a namespace" { } test "pointer loaded correctly from packed struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const RAM = struct { data: [0xFFFF + 1]u8, fn new() !@This() { @@ -1142,6 +1168,7 @@ test "assignment to non-byte-aligned field in packed struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Frame = packed struct { num: u20, @@ -1164,6 +1191,7 @@ test "packed struct field pointer aligned properly" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Foo = packed struct { a: i32, @@ -1183,6 +1211,7 @@ test "load flag from packed struct in union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = packed struct { a: bool, @@ -1251,6 +1280,7 @@ test "2-byte packed struct argument in C calling convention" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct(u16) { x: u15 = 0, diff --git a/test/behavior/packed-union.zig b/test/behavior/packed-union.zig index 55b76e2625..d76f28ae59 100644 --- a/test/behavior/packed-union.zig +++ b/test/behavior/packed-union.zig @@ -8,6 +8,7 @@ test "flags in packed union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFlagsInPackedUnion(); try comptime testFlagsInPackedUnion(); @@ -50,6 +51,7 @@ test "flags in packed union at offset" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testFlagsInPackedUnionAtOffset(); try comptime testFlagsInPackedUnionAtOffset(); @@ -98,6 +100,8 @@ fn testFlagsInPackedUnionAtOffset() !void { } test "packed union in packed struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + // Originally reported at https://github.com/ziglang/zig/issues/16581 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -137,6 +141,7 @@ test "packed union initialized with a runtime value" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Fields = packed struct { timestamp: u50, diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 27c6403e77..ffeeca3986 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -20,6 +20,7 @@ fn testDerefPtr() !void { test "pointer arithmetic" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var ptr: [*]const u8 = "abcd"; @@ -68,6 +69,7 @@ test "initialize const optional C pointer to null" { test "assigning integer to C pointer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: i32 = 0; var y: i32 = 1; @@ -85,6 +87,7 @@ test "assigning integer to C pointer" { test "C pointer comparison and arithmetic" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -154,6 +157,7 @@ test "implicit casting between C pointer and optional non-C pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var slice: []const u8 = "aoeu"; _ = &slice; @@ -170,6 +174,7 @@ test "implicit cast error unions with non-optional to optional pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -197,6 +202,7 @@ test "allowzero pointer and slice" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var ptr: [*]allowzero i32 = @ptrFromInt(0); const opt_ptr: ?[*]allowzero i32 = ptr; @@ -216,6 +222,7 @@ test "assign null directly to C pointer and test null equality" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: [*c]i32 = null; _ = &x; @@ -283,6 +290,7 @@ test "array initialization types" { test "null terminated pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -300,6 +308,7 @@ test "null terminated pointer" { test "allow any sentinel" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -315,6 +324,7 @@ test "allow any sentinel" { test "pointer sentinel with enums" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Number = enum { @@ -337,6 +347,7 @@ test "pointer sentinel with optional element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -353,6 +364,7 @@ test "pointer sentinel with +inf" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -430,6 +442,7 @@ test "indexing array with sentinel returns correct type" { test "element pointer to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -452,6 +465,7 @@ test "element pointer to slice" { test "element pointer arithmetic to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -476,6 +490,7 @@ test "element pointer arithmetic to slice" { test "array slicing to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -506,6 +521,7 @@ test "ptrCast comptime known slice to C pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const s: [:0]const u8 = "foo"; var p: [*c]const u8 = @ptrCast(s); @@ -525,6 +541,7 @@ test "pointer alignment and element type include call expression" { test "pointer to array has explicit alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Base = extern struct { a: u8 }; diff --git a/test/behavior/popcount.zig b/test/behavior/popcount.zig index 261019c65f..56a2171083 100644 --- a/test/behavior/popcount.zig +++ b/test/behavior/popcount.zig @@ -8,6 +8,7 @@ test "@popCount integers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testPopCountIntegers(); try testPopCountIntegers(); @@ -18,6 +19,7 @@ test "@popCount 128bit integer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; comptime { try expect(@popCount(@as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24); @@ -81,6 +83,7 @@ test "@popCount vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime testPopCountVectors(); try testPopCountVectors(); diff --git a/test/behavior/prefetch.zig b/test/behavior/prefetch.zig index e98e848393..1f21d23001 100644 --- a/test/behavior/prefetch.zig +++ b/test/behavior/prefetch.zig @@ -3,6 +3,7 @@ const std = @import("std"); test "@prefetch()" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: [2]u32 = .{ 42, 42 }; var a_len = a.len; diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index 11afc9474a..fc8a8b7482 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -58,6 +58,7 @@ fn testReinterpretStructWrappedBytesAsInteger() !void { test "reinterpret bytes of an array into an extern struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testReinterpretBytesAsExternStruct(); try comptime testReinterpretBytesAsExternStruct(); @@ -232,6 +233,7 @@ test "implicit optional pointer to optional anyopaque pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [4]u8 = "aoeu".*; const x: ?[*]u8 = &buf; @@ -244,6 +246,7 @@ test "@ptrCast slice to slice" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(slice: []u32) []i32 { diff --git a/test/behavior/ptrfromint.zig b/test/behavior/ptrfromint.zig index 89706be891..5e4c6175c3 100644 --- a/test/behavior/ptrfromint.zig +++ b/test/behavior/ptrfromint.zig @@ -3,6 +3,8 @@ const builtin = @import("builtin"); const expectEqual = std.testing.expectEqual; test "casting integer address to function pointer" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + addressToFunction(); comptime addressToFunction(); } @@ -17,6 +19,7 @@ test "mutate through ptr initialized with constant ptrFromInt value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; forceCompilerAnalyzeBranchHardCodedPtrDereference(false); } @@ -34,6 +37,7 @@ test "@ptrFromInt creates null pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const ptr = @as(?*u32, @ptrFromInt(0)); try expectEqual(@as(?*u32, null), ptr); @@ -43,6 +47,7 @@ test "@ptrFromInt creates allowzero zero pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const ptr = @as(*allowzero u32, @ptrFromInt(0)); try expectEqual(@as(usize, 0), @intFromPtr(ptr)); diff --git a/test/behavior/pub_enum.zig b/test/behavior/pub_enum.zig index c0935b78be..c749c82efe 100644 --- a/test/behavior/pub_enum.zig +++ b/test/behavior/pub_enum.zig @@ -4,6 +4,7 @@ const expect = @import("std").testing.expect; test "pub enum" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try pubEnumTest(other.APubEnum.Two); } @@ -13,6 +14,7 @@ fn pubEnumTest(foo: other.APubEnum) !void { test "cast with imported symbol" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@as(other.size_t, 42) == 42); } diff --git a/test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig index bb6d5b1359..366730424a 100644 --- a/test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig +++ b/test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig @@ -8,6 +8,7 @@ test "reference a variable in an if after an if in the 2nd switch prong" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try foo(true, Num.Two, false, "aoeu"); try expect(!ok); diff --git a/test/behavior/reflection.zig b/test/behavior/reflection.zig index aea84bc45a..f07b5a512e 100644 --- a/test/behavior/reflection.zig +++ b/test/behavior/reflection.zig @@ -28,6 +28,7 @@ fn dummy(a: bool, b: i32, c: f32) i32 { test "reflection: @field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var f = Foo{ .one = 42, diff --git a/test/behavior/return_address.zig b/test/behavior/return_address.zig index 3e8c18c04a..675e0e6191 100644 --- a/test/behavior/return_address.zig +++ b/test/behavior/return_address.zig @@ -10,6 +10,7 @@ test "return address" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; _ = retAddr(); // TODO: #14938 diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index 82d10d9540..843b3beaad 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -9,6 +9,7 @@ test "saturating add" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -57,6 +58,7 @@ test "saturating add 128bit" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -82,6 +84,7 @@ test "saturating subtraction" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -129,6 +132,7 @@ test "saturating subtraction 128bit" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -158,6 +162,7 @@ test "saturating multiplication" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) { // https://github.com/ziglang/zig/issues/9660 @@ -203,6 +208,7 @@ test "saturating shift-left" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -243,6 +249,7 @@ test "saturating shl uses the LHS type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const lhs_const: u8 = 1; var lhs_var: u8 = 1; diff --git a/test/behavior/select.zig b/test/behavior/select.zig index 2396d8bb11..90166dcfe5 100644 --- a/test/behavior/select.zig +++ b/test/behavior/select.zig @@ -9,6 +9,7 @@ test "@select vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try comptime selectVectors(); try selectVectors(); @@ -39,6 +40,7 @@ test "@select arrays" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx2)) return error.SkipZigTest; diff --git a/test/behavior/shuffle.zig b/test/behavior/shuffle.zig index 58c925b8fd..fb16f3fbb3 100644 --- a/test/behavior/shuffle.zig +++ b/test/behavior/shuffle.zig @@ -7,6 +7,7 @@ test "@shuffle int" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .ssse3)) return error.SkipZigTest; @@ -54,6 +55,7 @@ test "@shuffle bool 1" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) @@ -83,6 +85,7 @@ test "@shuffle bool 2" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/3246 diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index b6206df491..506baa2666 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -81,6 +81,7 @@ const P = packed struct { test "@offsetOf" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // Packed structs have fixed memory layout try expect(@offsetOf(P, "a") == 0); @@ -157,6 +158,7 @@ test "@TypeOf() has no runtime side effects" { test "branching logic inside @TypeOf" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { var data: i32 = 0; @@ -271,6 +273,7 @@ test "runtime instructions inside typeof in comptime only scope" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { var y: i8 = 2; @@ -327,6 +330,7 @@ test "peer type resolution with @TypeOf doesn't trigger dependency loop check" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = struct { next: @TypeOf(null, @as(*const @This(), undefined)), @@ -408,6 +412,7 @@ test "Extern function calls, dereferences and field access in @TypeOf" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Test = struct { fn test_fn_1(a: c_long) @TypeOf(c_fopen("test", "r").*) { diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index bf55f4f233..437d248127 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -30,6 +30,7 @@ comptime { test "slicing" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var array: [20]i32 = undefined; @@ -66,6 +67,7 @@ test "comptime slice of undefined pointer of length 0" { test "implicitly cast array of size 0 to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var msg = [_]u8{}; try assertLenIsZero(&msg); @@ -122,6 +124,7 @@ test "slice of type" { test "generic malloc free" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = memAlloc(u8, 10) catch unreachable; memFree(u8, a); @@ -183,6 +186,8 @@ test "slicing zero length array" { } test "slicing pointer by length" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; const ptr: [*]const u8 = @as([*]const u8, @ptrCast(&array)); const slice = ptr[1..][0..5]; @@ -231,6 +236,7 @@ test "runtime safety lets us slice from len..len" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var an_array = [_]u8{ 1, 2, 3 }; try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); @@ -243,6 +249,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { test "C pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; var len: u32 = 10; @@ -255,6 +262,7 @@ test "C pointer slice access" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [10]u32 = [1]u32{42} ** 10; const c_ptr = @as([*c]const u32, @ptrCast(&buf)); @@ -285,6 +293,7 @@ fn sliceSum(comptime q: []const u8) i32 { test "slice type with custom alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const LazilyResolvedType = struct { anything: i32, @@ -298,6 +307,7 @@ test "slice type with custom alignment" { test "obtaining a null terminated slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // here we have a normal array var buf: [50]u8 = undefined; @@ -342,6 +352,7 @@ test "empty array to slice" { test "@ptrCast slice to pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -357,6 +368,8 @@ test "@ptrCast slice to pointer" { } test "slice multi-pointer without end" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { try testPointer(); @@ -394,6 +407,7 @@ test "slice syntax resulting in pointer-to-array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -612,6 +626,7 @@ test "slice syntax resulting in pointer-to-array" { test "slice pointer-to-array null terminated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; comptime { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; @@ -630,6 +645,7 @@ test "slice pointer-to-array null terminated" { test "slice pointer-to-array zero length" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; comptime { { @@ -664,6 +680,7 @@ test "type coercion of pointer to anon struct literal to pointer to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const U = union { @@ -755,6 +772,7 @@ test "slice sentinel access at comptime" { test "slicing array with sentinel as end index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn do() !void { @@ -773,6 +791,7 @@ test "slicing array with sentinel as end index" { test "slicing slice with sentinel as end index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn do() !void { @@ -831,6 +850,7 @@ test "global slice field access" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { var slice: []const u8 = undefined; @@ -842,6 +862,8 @@ test "global slice field access" { } test "slice of void" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var n: usize = 10; _ = &n; var arr: [12]void = undefined; @@ -850,6 +872,8 @@ test "slice of void" { } test "slice with dereferenced value" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var a: usize = 0; const idx: *usize = &a; _ = blk: { @@ -884,6 +908,7 @@ test "empty slice ptr is non null" { test "slice decays to many pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var buf: [8]u8 = "abcdefg\x00".*; const p: [*:0]const u8 = buf[0..7 :0]; @@ -894,6 +919,7 @@ test "write through pointer to optional slice arg" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn bar(foo: *?[]const u8) !void { @@ -930,6 +956,7 @@ test "slicing zero length array field of struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: [0]usize, @@ -945,6 +972,7 @@ test "slicing slices gives correct result" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const foo = "1234"; const bar = foo[0..4]; @@ -959,6 +987,7 @@ test "get address of element of zero-sized slice" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn destroy(_: *void) void {} @@ -972,6 +1001,7 @@ test "sentinel-terminated 0-length slices" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const u32s: [4]u32 = [_]u32{ 0, 1, 2, 3 }; diff --git a/test/behavior/src.zig b/test/behavior/src.zig index ebf6ab06b0..7c2b377d5b 100644 --- a/test/behavior/src.zig +++ b/test/behavior/src.zig @@ -17,6 +17,7 @@ test "@src" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try doTheTest(); } @@ -37,6 +38,8 @@ test "@src used as a comptime parameter" { } test "@src in tuple passed to anytype function" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn Foo(a: anytype) u32 { return a[0].line; diff --git a/test/behavior/string_literals.zig b/test/behavior/string_literals.zig index 01f285bf0c..b1bb508503 100644 --- a/test/behavior/string_literals.zig +++ b/test/behavior/string_literals.zig @@ -34,6 +34,7 @@ const ptr_type_name: [*:0]const u8 = type_name; test "@typeName() returns a string literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name)); try std.testing.expect(std.mem.eql(u8, "behavior.string_literals.TestType", type_name)); @@ -47,6 +48,7 @@ const expected_contents = "hello zig\n"; test "@embedFile() returns a string literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try std.testing.expect(*const [expected_contents.len:0]u8 == @TypeOf(actual_contents)); try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents)); @@ -61,6 +63,7 @@ fn testFnForSrc() std.builtin.SourceLocation { test "@src() returns a struct containing 0-terminated string slices" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const src = testFnForSrc(); try std.testing.expect([:0]const u8 == @TypeOf(src.file)); diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 5ab3b0d38d..602be7e95e 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -68,6 +68,7 @@ const SmallStruct = struct { test "lower unnamed constants" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo = SmallStruct{ .a = 1, .b = 255 }; try expect(foo.first() == 1); @@ -91,6 +92,7 @@ test "structs" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo: StructFoo = undefined; @memset(@as([*]u8, @ptrCast(&foo))[0..@sizeOf(StructFoo)], 0); @@ -109,6 +111,7 @@ fn testMutation(foo: *StructFoo) void { test "struct byval assign" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo1: StructFoo = undefined; var foo2: StructFoo = undefined; @@ -173,6 +176,7 @@ const MemberFnTestFoo = struct { test "call member function directly" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const instance = MemberFnTestFoo{ .x = 1234 }; const result = MemberFnTestFoo.member(instance); @@ -181,6 +185,7 @@ test "call member function directly" { test "store member function in variable" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const instance = MemberFnTestFoo{ .x = 1234 }; const memberFn = MemberFnTestFoo.member; @@ -202,6 +207,7 @@ const MemberFnRand = struct { test "return struct byval from function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Bar = struct { x: i32, @@ -250,6 +256,7 @@ test "usingnamespace within struct scope" { test "struct field init with catch" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -293,6 +300,7 @@ const Val = struct { test "struct point to self" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var root: Node = undefined; root.val.x = 1; @@ -347,6 +355,7 @@ test "self-referencing struct via array member" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = struct { children: [1]*@This(), @@ -369,6 +378,7 @@ const EmptyStruct = struct { test "align 1 field before self referential align 8 field as slice return type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const result = alloc(Expr); try expect(result.len == 0); @@ -393,6 +403,7 @@ test "packed struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo = APackedStruct{ .x = 1, @@ -417,6 +428,7 @@ test "packed struct 24bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO if (comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -463,6 +475,7 @@ test "runtime struct initialization of bitfield" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const s1 = Nibbles{ .x = x1, @@ -502,6 +515,7 @@ test "packed struct fields are ordered from LSB to MSB" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var all: u64 = 0x7765443322221111; var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined; @@ -522,6 +536,7 @@ test "implicit cast packed struct field to const ptr" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const LevelUpMove = packed struct { move_id: u9, @@ -557,6 +572,7 @@ test "packed struct with non-ABI-aligned field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct { x: u9, @@ -586,6 +602,7 @@ test "bit field access" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var data = bit_field_1; try expect(getA(&data) == 1); @@ -616,6 +633,7 @@ fn getC(data: *const BitField1) u2 { test "default struct initialization fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: i32 = 1234, @@ -642,6 +660,7 @@ test "packed array 24bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; comptime { try expect(@sizeOf([9]Foo32Bits) == 9 * 4); @@ -709,6 +728,7 @@ test "pointer to packed struct member in a stack variable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct { a: u2, @@ -761,6 +781,7 @@ test "packed struct with fp fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = packed struct { data0: f32, @@ -788,6 +809,7 @@ test "fn with C calling convention returns struct by value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -815,6 +837,7 @@ test "non-packed struct with u128 entry in union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { Num: u128, @@ -863,6 +886,7 @@ test "packed struct field passed to generic function" { test "anonymous struct literal syntax" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Point = struct { @@ -885,6 +909,8 @@ test "anonymous struct literal syntax" { } test "fully anonymous struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { try dump(.{ @@ -907,6 +933,8 @@ test "fully anonymous struct" { } test "fully anonymous list literal" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" }); @@ -954,6 +982,7 @@ test "tuple element initialized with fn call" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -972,6 +1001,7 @@ test "struct with union field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Value = struct { ref: u32 = 2, @@ -993,6 +1023,7 @@ test "struct with 0-length union array field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union { a: u32, @@ -1013,6 +1044,7 @@ test "type coercion of anon struct literal to struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const S2 = struct { @@ -1052,6 +1084,7 @@ test "type coercion of pointer to anon struct literal to pointer to struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const S2 = struct { @@ -1091,6 +1124,7 @@ test "packed struct with undefined initializers" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const P = packed struct { @@ -1120,6 +1154,7 @@ test "packed struct with undefined initializers" { test "for loop over pointers to struct, getting field from struct pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Foo = struct { @@ -1160,6 +1195,7 @@ test "anon init through error unions and optionals" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -1187,6 +1223,7 @@ test "anon init through optional" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -1207,6 +1244,7 @@ test "anon init through error union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -1226,6 +1264,7 @@ test "typed init through error unions and optionals" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: u32, @@ -1260,6 +1299,7 @@ test "initialize struct with empty literal" { test "loading a struct pointer perfoms a copy" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: i32, @@ -1288,6 +1328,7 @@ test "packed struct aggregate init" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(a: i2, b: i6) u8 { @@ -1347,6 +1388,7 @@ test "store to comptime field" { test "struct field init value is size of the struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const namespace = struct { const S = extern struct { @@ -1364,6 +1406,7 @@ test "under-aligned struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = extern union { fd: i32, @@ -1386,6 +1429,7 @@ test "fieldParentPtr of a zero-bit field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn testStruct(comptime A: type) !void { @@ -1444,6 +1488,8 @@ test "struct field has a pointer to an aligned version of itself" { } test "struct has only one reference" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn optionalStructParam(_: ?struct { x: u8 }) void {} fn errorUnionStructParam(_: error{}!struct { x: u8 }) void {} @@ -1493,6 +1539,7 @@ test "no dependency loop on pointer to optional struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const A = struct { b: B }; @@ -1514,6 +1561,7 @@ test "discarded struct initialization works as expected" { test "function pointer in struct returns the struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = struct { const A = @This(); @@ -1549,6 +1597,7 @@ test "no dependency loop on optional field wrapped in generic function" { test "optional field init with tuple" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: ?struct { b: u32 }, @@ -1563,6 +1612,7 @@ test "optional field init with tuple" { test "if inside struct init inside if" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const MyStruct = struct { x: u32 }; const b: u32 = 5; @@ -1682,6 +1732,7 @@ test "extern struct field pointer has correct alignment" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1719,6 +1770,8 @@ test "extern struct field pointer has correct alignment" { } test "packed struct field in anonymous struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const T = packed struct { f1: bool = false, }; @@ -1730,6 +1783,8 @@ fn countFields(v: anytype) usize { } test "struct init with no result pointer sets field result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { // A function parameter has a result type, but no result pointer. fn f(s: struct { x: u32 }) u32 { @@ -1744,6 +1799,8 @@ test "struct init with no result pointer sets field result types" { } test "runtime side-effects in comptime-known struct init" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var side_effects: u4 = 0; const S = struct { a: u4, b: u4, c: u4, d: u4 }; const init = S{ @@ -1769,6 +1826,8 @@ test "runtime side-effects in comptime-known struct init" { } test "pointer to struct initialized through reference to anonymous initializer provides result types" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { a: u8, b: u16, c: *const anyopaque }; var my_u16: u16 = 0xABCD; _ = &my_u16; @@ -1804,6 +1863,8 @@ test "comptimeness of optional and error union payload is analyzed properly" { } test "initializer uses own alignment" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { x: u32 = @alignOf(@This()) + 1, }; @@ -1815,6 +1876,8 @@ test "initializer uses own alignment" { } test "initializer uses own size" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { x: u32 = @sizeOf(@This()) + 1, }; @@ -1826,6 +1889,8 @@ test "initializer uses own size" { } test "initializer takes a pointer to a variable inside its struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const namespace = struct { const S = struct { s: *S = &S.instance, @@ -1844,6 +1909,8 @@ test "initializer takes a pointer to a variable inside its struct" { } test "circular dependency through pointer field of a struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { const StructInner = extern struct { outer: StructOuter = std.mem.zeroes(StructOuter), @@ -1865,6 +1932,8 @@ test "circular dependency through pointer field of a struct" { } test "field calls do not force struct field init resolution" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { x: u32 = blk: { _ = @TypeOf(make().dummyFn()); // runtime field call - S not fully resolved - dummyFn call should not force field init resolution @@ -1914,6 +1983,7 @@ test "assign to slice.len of global variable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const allocator = std.testing.allocator; @@ -1964,6 +2034,7 @@ test "runtime call in nested initializer" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Holder = struct { array: []const u8, @@ -1996,6 +2067,7 @@ test "runtime value in nested initializer passed as pointer to function" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Bar = struct { b: u32, @@ -2070,6 +2142,7 @@ test "assignment of field with padding" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Mesh = extern struct { id: u32, @@ -2100,6 +2173,7 @@ test "initiate global variable with runtime value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { field: i32, @@ -2118,6 +2192,7 @@ test "initiate global variable with runtime value" { test "struct containing optional pointer to array of @This()" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { x: ?*const [1]@This(), diff --git a/test/behavior/struct_contains_null_ptr_itself.zig b/test/behavior/struct_contains_null_ptr_itself.zig index d0cb3ef443..d3dacc50cd 100644 --- a/test/behavior/struct_contains_null_ptr_itself.zig +++ b/test/behavior/struct_contains_null_ptr_itself.zig @@ -5,6 +5,7 @@ const builtin = @import("builtin"); test "struct contains null pointer which contains original struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: ?*NodeLineComment = null; _ = &x; diff --git a/test/behavior/struct_contains_slice_of_itself.zig b/test/behavior/struct_contains_slice_of_itself.zig index adb1c31047..6f6d829567 100644 --- a/test/behavior/struct_contains_slice_of_itself.zig +++ b/test/behavior/struct_contains_slice_of_itself.zig @@ -13,6 +13,7 @@ const NodeAligned = struct { test "struct contains slice of itself" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var other_nodes = [_]Node{ Node{ @@ -53,6 +54,7 @@ test "struct contains slice of itself" { test "struct contains aligned slice of itself" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var other_nodes = [_]NodeAligned{ NodeAligned{ diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index c36b4a520d..78365e8763 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -7,6 +7,7 @@ const expectEqual = std.testing.expectEqual; test "switch with numbers" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSwitchWithNumbers(13); } @@ -22,6 +23,7 @@ fn testSwitchWithNumbers(x: u32) !void { test "switch with all ranges" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(testSwitchWithAllRanges(50, 3) == 1); try expect(testSwitchWithAllRanges(101, 0) == 2); @@ -55,6 +57,7 @@ test "implicit comptime switch" { test "switch on enum" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const fruit = Fruit.Orange; nonConstSwitchOnEnum(fruit); @@ -74,6 +77,7 @@ fn nonConstSwitchOnEnum(fruit: Fruit) void { test "switch statement" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try nonConstSwitch(SwitchStatementFoo.C); } @@ -90,6 +94,7 @@ const SwitchStatementFoo = enum { A, B, C, D }; test "switch with multiple expressions" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const x = switch (returnsFive()) { 1, 2, 3 => 1, @@ -118,6 +123,7 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool { test "switching on booleans" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSwitchOnBools(); try comptime testSwitchOnBools(); @@ -173,6 +179,7 @@ test "undefined.u0" { test "switch with disjoint range" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var q: u8 = 0; _ = &q; @@ -184,6 +191,8 @@ test "switch with disjoint range" { } test "switch variable for range and multiple prongs" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { try doTheSwitch(16); @@ -215,6 +224,7 @@ fn poll() void { test "switch on global mutable var isn't constant-folded" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; while (state < 2) { poll(); @@ -231,6 +241,7 @@ test "switch prong with variable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); @@ -255,6 +266,7 @@ test "switch on enum using pointer capture" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSwitchEnumPtrCapture(); try comptime testSwitchEnumPtrCapture(); @@ -274,6 +286,7 @@ fn testSwitchEnumPtrCapture() !void { test "switch handles all cases of number" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testSwitchHandleAllCases(); try comptime testSwitchHandleAllCases(); @@ -315,6 +328,7 @@ test "switch on union with some prongs capturing" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const X = union(enum) { a, @@ -368,6 +382,7 @@ test "anon enum literal used in switch on union enum" { test "switch all prongs unreachable" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testAllProngsUnreachable(); try comptime testAllProngsUnreachable(); @@ -391,6 +406,7 @@ fn switchWithUnreachable(x: i32) i32 { test "capture value of switch with all unreachable prongs" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const x = return_a_number() catch |err| switch (err) { else => unreachable, @@ -404,6 +420,7 @@ fn return_a_number() anyerror!i32 { test "switch on integer with else capturing expr" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -425,6 +442,7 @@ test "else prong of switch on error set excludes other cases" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -460,6 +478,7 @@ test "switch prongs with error set cases make a new error set type for capture v if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -494,6 +513,7 @@ test "switch prongs with error set cases make a new error set type for capture v test "return result loc and then switch with range implicit casted to error union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -514,6 +534,7 @@ test "switch with null and T peer types and inferred result location type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest(c: u8) !void { @@ -534,6 +555,7 @@ test "switch prongs with cases with identical payload types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Union = union(enum) { A: usize, @@ -640,6 +662,7 @@ test "switch prong pointer capture alignment" { test "switch on pointer type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const X = struct { @@ -688,6 +711,7 @@ test "switch capture copies its payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -711,6 +735,7 @@ test "switch capture copies its payload" { test "capture of integer forwards the switch condition directly" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(x: u8) !void { @@ -732,6 +757,7 @@ test "capture of integer forwards the switch condition directly" { test "enum value without tag name used as switch item" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = enum(u32) { a = 1, @@ -749,6 +775,8 @@ test "enum value without tag name used as switch item" { } test "switch item sizeof" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var a: usize = 0; @@ -777,6 +805,8 @@ test "comptime inline switch" { } test "switch capture peer type resolution" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const U = union(enum) { a: u32, b: u64, @@ -792,6 +822,8 @@ test "switch capture peer type resolution" { } test "switch capture peer type resolution for in-memory coercible payloads" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const T1 = c_int; const T2 = @Type(@typeInfo(T1)); @@ -813,6 +845,7 @@ test "switch capture peer type resolution for in-memory coercible payloads" { test "switch pointer capture peer type resolution" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T1 = c_int; const T2 = @Type(@typeInfo(T1)); @@ -840,6 +873,8 @@ test "switch pointer capture peer type resolution" { } test "inline switch range that includes the maximum value of the switched type" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const inputs: [3]u8 = .{ 0, 254, 255 }; for (inputs) |input| { switch (input) { @@ -850,6 +885,8 @@ test "inline switch range that includes the maximum value of the switched type" } test "nested break ignores switch conditions and breaks instead" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn register_to_address(ident: []const u8) !u8 { const reg: u8 = if (std.mem.eql(u8, ident, "zero")) 0x00 else blk: { @@ -870,6 +907,7 @@ test "nested break ignores switch conditions and breaks instead" { test "peer type resolution on switch captures ignores unused payload bits" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Foo = union(enum) { a: u32, @@ -895,6 +933,7 @@ test "peer type resolution on switch captures ignores unused payload bits" { test "switch prong captures range" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn a(b: []u3, c: u3) void { @@ -912,6 +951,8 @@ test "switch prong captures range" { } test "prong with inline call to unreachable" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const U = union(enum) { void: void, bool: bool, @@ -929,6 +970,8 @@ test "prong with inline call to unreachable" { } test "block error return trace index is reset between prongs" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn returnError() error{TestFailed} { return error.TestFailed; diff --git a/test/behavior/switch_on_captured_error.zig b/test/behavior/switch_on_captured_error.zig index 6e70c851b1..a4bdc8755f 100644 --- a/test/behavior/switch_on_captured_error.zig +++ b/test/behavior/switch_on_captured_error.zig @@ -8,6 +8,7 @@ const builtin = @import("builtin"); test "switch on error union catch capture" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Error = error{ A, B, C }; @@ -302,6 +303,7 @@ test "switch on error union catch capture" { test "switch on error union if else capture" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Error = error{ A, B, C }; diff --git a/test/behavior/switch_prong_err_enum.zig b/test/behavior/switch_prong_err_enum.zig index 15d366d04f..8d622ed4d4 100644 --- a/test/behavior/switch_prong_err_enum.zig +++ b/test/behavior/switch_prong_err_enum.zig @@ -24,6 +24,7 @@ test "switch prong returns error enum" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; switch (doThing(17) catch unreachable) { FormValue.Address => |payload| { diff --git a/test/behavior/switch_prong_implicit_cast.zig b/test/behavior/switch_prong_implicit_cast.zig index 54107bb6bd..2281ddd448 100644 --- a/test/behavior/switch_prong_implicit_cast.zig +++ b/test/behavior/switch_prong_implicit_cast.zig @@ -18,6 +18,7 @@ test "switch prong implicit cast" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const result = switch (foo(2) catch unreachable) { FormValue.One => false, diff --git a/test/behavior/this.zig b/test/behavior/this.zig index 3f8fe13316..330f9a714d 100644 --- a/test/behavior/this.zig +++ b/test/behavior/this.zig @@ -27,6 +27,7 @@ test "this refer to module call private fn" { test "this refer to container" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var pt: Point(i32) = undefined; pt.x = 12; @@ -50,6 +51,7 @@ test "this used as optional function parameter" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var global: State = undefined; global.enter = prev; diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig index f91e10d12d..87daebda78 100644 --- a/test/behavior/threadlocal.zig +++ b/test/behavior/threadlocal.zig @@ -6,6 +6,7 @@ test "thread local variable" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { .x86_64, .x86 => {}, else => return error.SkipZigTest, @@ -28,6 +29,7 @@ test "pointer to thread local array" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { .x86_64, .x86 => {}, else => return error.SkipZigTest, @@ -45,6 +47,7 @@ test "reference a global threadlocal variable" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { .x86_64, .x86 => {}, else => return error.SkipZigTest, diff --git a/test/behavior/truncate.zig b/test/behavior/truncate.zig index 267d291d48..404b9f6d71 100644 --- a/test/behavior/truncate.zig +++ b/test/behavior/truncate.zig @@ -69,6 +69,7 @@ test "truncate on vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { diff --git a/test/behavior/try.zig b/test/behavior/try.zig index cc76658e93..e8ab96e5c9 100644 --- a/test/behavior/try.zig +++ b/test/behavior/try.zig @@ -4,6 +4,7 @@ const expect = std.testing.expect; test "try on error union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try tryOnErrorUnionImpl(); try comptime tryOnErrorUnionImpl(); @@ -51,6 +52,7 @@ test "`try`ing an if/else expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn getError() !void { diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 2b52df45a1..736bbad806 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -10,6 +10,7 @@ test "tuple concatenation" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -55,6 +56,7 @@ test "more tuple concatenation" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = struct { fn consume_tuple(tuple: anytype, len: usize) !void { @@ -131,6 +133,7 @@ test "tuple initializer for var" { test "array-like initializer for tuple types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = @Type(.{ .Struct = .{ @@ -218,6 +221,7 @@ test "fieldParentPtr of tuple" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u32 = 0; _ = &x; @@ -229,6 +233,7 @@ test "fieldParentPtr of anon struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u32 = 0; _ = &x; @@ -278,6 +283,7 @@ test "tuple in tuple passed to generic function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn pair(x: f32, y: f32) std.meta.Tuple(&.{ f32, f32 }) { @@ -297,6 +303,7 @@ test "coerce tuple to tuple" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = std.meta.Tuple(&.{u8}); const S = struct { @@ -311,6 +318,7 @@ test "tuple type with void field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = std.meta.Tuple(&[_]type{void}); const x = T{{}}; @@ -318,6 +326,8 @@ test "tuple type with void field" { } test "zero sized struct in tuple handled correctly" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const State = struct { const Self = @This(); data: @Type(.{ @@ -347,6 +357,7 @@ test "zero sized struct in tuple handled correctly" { test "tuple type with void field and a runtime field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = std.meta.Tuple(&[_]type{ usize, void }); var t: T = .{ 5, {} }; @@ -358,6 +369,7 @@ test "branching inside tuple literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn foo(a: anytype) !void { @@ -373,6 +385,7 @@ test "tuple initialized with a runtime known value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = union(enum) { e: []const u8 }; const W = union(enum) { w: E }; @@ -387,6 +400,7 @@ test "tuple of struct concatenation and coercion to array" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const StructWithDefault = struct { value: f32 = 42 }; const SomeStruct = struct { array: [4]StructWithDefault }; @@ -401,6 +415,7 @@ test "nested runtime conditionals in tuple initializer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var data: u8 = 0; _ = &data; @@ -459,6 +474,7 @@ test "coerce anon tuple to tuple" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u8 = 1; var y: u16 = 2; @@ -493,6 +509,7 @@ test "tuple with runtime value coerced into a slice with a sentinel" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn f(a: [:null]const ?u8) !void { @@ -562,6 +579,8 @@ test "comptime fields in tuple can be initialized" { } test "tuple default values" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const T = struct { usize, usize = 123, diff --git a/test/behavior/tuple_declarations.zig b/test/behavior/tuple_declarations.zig index e6d5d76fc8..dc9214e7bb 100644 --- a/test/behavior/tuple_declarations.zig +++ b/test/behavior/tuple_declarations.zig @@ -7,6 +7,7 @@ const expectEqualStrings = testing.expectEqualStrings; test "tuple declaration type info" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; { const T = struct { comptime u32 align(2) = 1, []const u8 }; @@ -35,6 +36,7 @@ test "tuple declaration type info" { test "Tuple declaration usage" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = struct { u32, []const u8 }; var t: T = .{ 1, "foo" }; diff --git a/test/behavior/type.zig b/test/behavior/type.zig index ba29640774..6150a490cf 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -203,6 +203,7 @@ test "Type.Opaque" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Opaque = @Type(.{ .Opaque = .{ @@ -260,6 +261,7 @@ test "Type.Struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = @Type(@typeInfo(struct { x: u8, y: u32 })); const infoA = @typeInfo(A).Struct; @@ -383,6 +385,7 @@ test "Type.Union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Untagged = @Type(.{ .Union = .{ diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index b650248e42..9ac5e25e89 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -565,6 +565,8 @@ test "StructField.is_comptime" { } test "typeInfo resolves usingnamespace declarations" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const A = struct { pub const f1 = 42; }; @@ -590,6 +592,7 @@ test "value from struct @typeInfo default_value can be loaded at comptime" { test "@typeInfo decls and usingnamespace" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const A = struct { pub const x = 5; @@ -630,6 +633,8 @@ test "type info of tuple of string literal default value" { } test "@typeInfo only contains pub decls" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const other = struct { const std = @import("std"); diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig index c3eefc8de7..e5ebbb6f47 100644 --- a/test/behavior/typename.zig +++ b/test/behavior/typename.zig @@ -16,6 +16,7 @@ test "anon fn param" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/9339 try expectEqualStringsIgnoreDigits( @@ -41,6 +42,7 @@ test "anon field init" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Foo = .{ .T1 = struct {}, @@ -66,6 +68,7 @@ test "basic" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expectEqualStrings("i64", @typeName(i64)); try expectEqualStrings("*usize", @typeName(*usize)); @@ -87,6 +90,7 @@ test "top level decl" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expectEqualStrings( "behavior.typename.A_Struct", @@ -136,6 +140,7 @@ test "fn param" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/675 try expectEqualStrings( @@ -215,6 +220,7 @@ test "local variable" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Foo = struct { a: u32 }; const Bar = union { a: u32 }; @@ -233,6 +239,7 @@ test "comptime parameters not converted to anytype in function type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = fn (fn (type) void, void) void; try expectEqualStrings("fn (comptime fn (comptime type) void, void) void", @typeName(T)); @@ -242,6 +249,7 @@ test "anon name strategy used in sub expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn getTheName() []const u8 { diff --git a/test/behavior/undefined.zig b/test/behavior/undefined.zig index adda49cfe0..bc613585d3 100644 --- a/test/behavior/undefined.zig +++ b/test/behavior/undefined.zig @@ -91,6 +91,7 @@ test "reslice of undefined global var slice" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var stack_buf: [100]u8 = [_]u8{0} ** 100; buf = &stack_buf; @@ -103,6 +104,7 @@ test "returned undef is 0xaa bytes when runtime safety is enabled" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Rect = struct { x: f32, diff --git a/test/behavior/underscore.zig b/test/behavior/underscore.zig index 66b49e52d5..a53fec489b 100644 --- a/test/behavior/underscore.zig +++ b/test/behavior/underscore.zig @@ -8,6 +8,7 @@ test "ignore lval with underscore" { test "ignore lval with underscore (while loop)" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; while (optionalReturnError()) |_| { while (optionalReturnError()) |_| { diff --git a/test/behavior/union.zig b/test/behavior/union.zig index b652d52896..62997d097a 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -15,6 +15,7 @@ test "basic unions with floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo = FooWithFloats{ .int = 1 }; try expect(foo.int == 1); @@ -30,6 +31,7 @@ test "init union with runtime value - floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo: FooWithFloats = undefined; @@ -41,6 +43,7 @@ test "basic unions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo = Foo{ .int = 1 }; try expect(foo.int == 1); @@ -59,6 +62,7 @@ test "init union with runtime value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo: Foo = undefined; @@ -97,6 +101,7 @@ const FooExtern = extern union { test "basic extern unions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var foo = FooExtern{ .int = 1 }; try expect(foo.int == 1); @@ -168,6 +173,7 @@ test "constant tagged union with payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var empty = TaggedUnionWithPayload{ .Empty = {} }; var full = TaggedUnionWithPayload{ .Full = 13 }; @@ -218,6 +224,7 @@ test "union with specified enum tag" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try doTest(); try comptime doTest(); @@ -228,6 +235,7 @@ test "packed union generates correctly aligned type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = packed union { f1: *const fn () error{TestUnexpectedResult}!void, @@ -268,6 +276,7 @@ test "comparison between union and enum literal" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testComparison(); try comptime testComparison(); @@ -283,6 +292,7 @@ test "cast union to tag type of union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testCastUnionToTag(); try comptime testCastUnionToTag(); @@ -304,6 +314,7 @@ test "cast tag type of union to union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: Value2 = Letter2.B; _ = &x; @@ -320,6 +331,7 @@ test "implicit cast union to its tag type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: Value2 = Letter2.B; _ = &x; @@ -341,6 +353,7 @@ test "constant packed union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); } @@ -405,6 +418,7 @@ test "tagged union initialization with runtime void" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(testTaggedUnionInit({})); } @@ -490,6 +504,7 @@ test "initialize global array of union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; glbl_array[1] = FooUnion{ .U1 = 2 }; glbl_array[0] = FooUnion{ .U0 = 1 }; @@ -501,6 +516,7 @@ test "update the tag value for zero-sized unions" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = union(enum) { U0: void, @@ -605,6 +621,7 @@ test "tagged union as return value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; switch (returnAnInt(13)) { TaggedFoo.One => |value| try expect(value == 13), @@ -620,6 +637,7 @@ test "tagged union with all void fields but a meaningful tag" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const B = union(enum) { @@ -648,6 +666,7 @@ test "union(enum(u32)) with specified and unspecified tag values" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; comptime assert(Tag(Tag(MultipleChoice2)) == u32); try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); @@ -740,6 +759,7 @@ test "@intFromEnum works on unions" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Bar = union(enum) { A: bool, @@ -799,6 +819,7 @@ test "return union init with void payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -823,6 +844,7 @@ test "@unionInit stored to a const" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const U = union(enum) { @@ -853,6 +875,7 @@ test "@unionInit can modify a union type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const UnionInitEnum = union(enum) { Boolean: bool, @@ -876,6 +899,7 @@ test "@unionInit can modify a pointer value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const UnionInitEnum = union(enum) { Boolean: bool, @@ -931,6 +955,7 @@ test "anonymous union literal syntax" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Number = union { @@ -958,6 +983,7 @@ test "function call result coerces from tagged union to the tag" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Arch = union(enum) { @@ -993,6 +1019,7 @@ test "cast from anonymous struct to union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const U = union(enum) { @@ -1027,6 +1054,7 @@ test "cast from pointer to anonymous struct to pointer to union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const U = union(enum) { @@ -1061,6 +1089,7 @@ test "switching on non exhaustive union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const E = enum(u8) { @@ -1120,6 +1149,7 @@ test "@unionInit on union with tag but no fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const Type = enum(u8) { no_op = 105 }; @@ -1169,6 +1199,7 @@ test "global variable struct contains union initialized to non-most-aligned fiel if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const T = struct { const U = union(enum) { @@ -1195,6 +1226,7 @@ test "union with no result loc initiated with a runtime value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union { a: u32, @@ -1212,6 +1244,7 @@ test "union with a large struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { a: [8]usize, @@ -1246,6 +1279,7 @@ test "union tag is set when initiated as a temporary value at runtime" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { a, @@ -1266,6 +1300,7 @@ test "extern union most-aligned field is smaller" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = extern union { in6: extern struct { @@ -1285,6 +1320,7 @@ test "return an extern union from C calling convention" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const namespace = struct { const S = extern struct { @@ -1316,6 +1352,7 @@ test "noreturn field in union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { a: u32, @@ -1367,6 +1404,7 @@ test "@unionInit uses tag value instead of field index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = enum(u8) { b = 255, @@ -1396,6 +1434,7 @@ test "union field ptr - zero sized payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union { foo: void, @@ -1410,6 +1449,7 @@ test "union field ptr - zero sized field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union { foo: void, @@ -1476,6 +1516,7 @@ test "no dependency loop when function pointer in union returns the union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { const U = @This(); @@ -1496,6 +1537,7 @@ test "no dependency loop when function pointer in union returns the union" { test "union reassignment can use previous value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union { a: u32, @@ -1547,6 +1589,7 @@ test "reinterpreting enum value inside packed union" { test "access the tag of a global tagged union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { a, @@ -1558,6 +1601,7 @@ test "access the tag of a global tagged union" { test "coerce enum literal to union in result loc" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { a, @@ -1675,6 +1719,7 @@ test "packed union field pointer has correct alignment" { test "union with 128 bit integer" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const ValueTag = enum { int, other }; @@ -1698,6 +1743,7 @@ test "union with 128 bit integer" { test "memset extern union" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = extern union { foo: u8, @@ -1719,6 +1765,7 @@ test "memset extern union" { test "memset packed union" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = packed union { a: u32, @@ -1819,6 +1866,7 @@ test "reinterpret extern union" { test "reinterpret packed union" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = packed union { foo: u8, @@ -1891,6 +1939,7 @@ test "reinterpret packed union" { test "reinterpret packed union inside packed struct" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = packed union { a: u7, @@ -1927,6 +1976,8 @@ test "reinterpret packed union inside packed struct" { } test "inner struct initializer uses union layout" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const namespace = struct { const U = union { a: struct { @@ -1952,6 +2003,7 @@ test "inner struct initializer uses union layout" { test "inner struct initializer uses packed union layout" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const namespace = struct { const U = packed union { @@ -1978,6 +2030,7 @@ test "inner struct initializer uses packed union layout" { test "extern union initialized via reintepreted struct field initializer" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; @@ -1997,6 +2050,7 @@ test "extern union initialized via reintepreted struct field initializer" { test "packed union initialized via reintepreted struct field initializer" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; @@ -2017,6 +2071,7 @@ test "packed union initialized via reintepreted struct field initializer" { test "store of comptime reinterpreted memory to extern union" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; @@ -2039,6 +2094,7 @@ test "store of comptime reinterpreted memory to extern union" { test "store of comptime reinterpreted memory to packed union" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; @@ -2061,6 +2117,7 @@ test "store of comptime reinterpreted memory to packed union" { test "union field is a pointer to an aligned version of itself" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const E = union { next: *align(1) @This(), @@ -2072,6 +2129,8 @@ test "union field is a pointer to an aligned version of itself" { } test "pass register-sized field as non-register-sized union" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const S = struct { fn taggedUnion(u: union(enum) { x: usize, y: [2]usize }) !void { try expectEqual(@as(usize, 42), u.x); @@ -2095,6 +2154,7 @@ test "pass register-sized field as non-register-sized union" { test "circular dependency through pointer field of a union" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { const UnionInner = extern struct { @@ -2117,6 +2177,8 @@ test "circular dependency through pointer field of a union" { } test "pass nested union with rls" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const Union = union(enum) { a: u32, b: union(enum) { @@ -2139,6 +2201,7 @@ test "runtime union init, most-aligned field != largest" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { x: u128, @@ -2163,6 +2226,7 @@ test "copied union field doesn't alias source" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const U = union(enum) { array: [10]u32, @@ -2183,6 +2247,7 @@ test "create union(enum) from other union(enum)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const string = "hello world"; const TempRef = struct { @@ -2308,6 +2373,7 @@ test "signed enum tag with negative value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Enum = enum(i8) { a = -1, diff --git a/test/behavior/union_with_members.zig b/test/behavior/union_with_members.zig index 186a30ad63..83ce38d5bc 100644 --- a/test/behavior/union_with_members.zig +++ b/test/behavior/union_with_members.zig @@ -21,6 +21,7 @@ test "enum with members" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const a = ET{ .SINT = -42 }; const b = ET{ .UINT = 42 }; diff --git a/test/behavior/usingnamespace.zig b/test/behavior/usingnamespace.zig index 61b4137cde..9be734dd32 100644 --- a/test/behavior/usingnamespace.zig +++ b/test/behavior/usingnamespace.zig @@ -11,6 +11,8 @@ const C = struct { }; test "basic usingnamespace" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try std.testing.expect(C.B == bool); } @@ -21,6 +23,8 @@ fn Foo(comptime T: type) type { } test "usingnamespace inside a generic struct" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + const std2 = Foo(std); const testing2 = Foo(std.testing); try std2.testing.expect(true); @@ -32,6 +36,8 @@ usingnamespace struct { }; test "usingnamespace does not redeclare an imported variable" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try comptime std.testing.expect(@This().foo == 42); } @@ -39,6 +45,7 @@ usingnamespace @import("usingnamespace/foo.zig"); test "usingnamespace omits mixing in private functions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@This().privateFunction()); try expect(!@This().printText()); @@ -48,6 +55,8 @@ fn privateFunction() bool { } test { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + _ = @import("usingnamespace/import_segregation.zig"); } @@ -55,6 +64,7 @@ usingnamespace @import("usingnamespace/a.zig"); test "two files usingnamespace import each other" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@This().ok()); } @@ -62,6 +72,7 @@ test "two files usingnamespace import each other" { test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const AA = struct { x: i32, @@ -94,6 +105,8 @@ const Mixin = struct { }; test "container member access usingnamespace decls" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var foo = Bar{}; foo.two(); } diff --git a/test/behavior/usingnamespace/file_1.zig b/test/behavior/usingnamespace/file_1.zig index 971fb8958d..e16ae80e48 100644 --- a/test/behavior/usingnamespace/file_1.zig +++ b/test/behavior/usingnamespace/file_1.zig @@ -1,9 +1,12 @@ const std = @import("std"); const expect = std.testing.expect; const imports = @import("imports.zig"); +const builtin = @import("builtin"); const A = 456; test { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(imports.A == 123); } diff --git a/test/behavior/usingnamespace/import_segregation.zig b/test/behavior/usingnamespace/import_segregation.zig index f1dffc6383..f06a5bb4f6 100644 --- a/test/behavior/usingnamespace/import_segregation.zig +++ b/test/behavior/usingnamespace/import_segregation.zig @@ -6,6 +6,7 @@ usingnamespace @import("bar.zig"); test "no clobbering happened" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) { // https://github.com/ziglang/zig/issues/16846 diff --git a/test/behavior/var_args.zig b/test/behavior/var_args.zig index b0dccc1383..a3d4f09d2e 100644 --- a/test/behavior/var_args.zig +++ b/test/behavior/var_args.zig @@ -14,6 +14,8 @@ fn add(args: anytype) i32 { } test "add arbitrary args" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); try expect(add(.{@as(i32, 1234)}) == 1234); try expect(add(.{}) == 0); @@ -24,12 +26,15 @@ fn readFirstVarArg(args: anytype) void { } test "send void arg to var args" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + readFirstVarArg(.{{}}); } test "pass args directly" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234); @@ -43,6 +48,7 @@ fn addSomeStuff(args: anytype) i32 { test "runtime parameter before var args" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect((try extraFn(10, .{})) == 0); try expect((try extraFn(10, .{false})) == 1); @@ -81,11 +87,15 @@ fn foo2(args: anytype) bool { } test "array of var args functions" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + try expect(foos[0](.{})); try expect(!foos[1](.{})); } test "pass zero length array to var args param" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + doNothingWithFirstArg(.{""}); } @@ -99,6 +109,7 @@ test "simple variadic function" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) { // https://github.com/ziglang/zig/issues/14096 return error.SkipZigTest; @@ -158,6 +169,7 @@ test "coerce reference to var arg" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) { // https://github.com/ziglang/zig/issues/14096 return error.SkipZigTest; @@ -189,6 +201,7 @@ test "variadic functions" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) { // https://github.com/ziglang/zig/issues/14096 return error.SkipZigTest; @@ -232,6 +245,7 @@ test "copy VaList" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) { // https://github.com/ziglang/zig/issues/14096 return error.SkipZigTest; @@ -264,6 +278,7 @@ test "unused VaList arg" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) { // https://github.com/ziglang/zig/issues/14096 return error.SkipZigTest; diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 8a23954c76..688b36a911 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -28,6 +28,7 @@ test "vector wrap operators" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; @@ -52,6 +53,7 @@ test "vector bin compares with mem.eql" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -76,6 +78,7 @@ test "vector int operators" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -100,6 +103,7 @@ test "vector float operators" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { const S = struct { @@ -123,6 +127,7 @@ test "vector bit operators" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -142,6 +147,7 @@ test "implicit cast vector to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -160,6 +166,7 @@ test "array to vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -180,6 +187,7 @@ test "array vector coercion - odd sizes" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -219,6 +227,7 @@ test "array to vector with element type coercion" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -258,6 +267,7 @@ test "tuple to vector" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { // Regressed with LLVM 14: @@ -287,6 +297,7 @@ test "vector casts of sizes not divisible by 8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -325,6 +336,7 @@ test "vector @splat" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .macos) @@ -371,6 +383,7 @@ test "load vector elements via comptime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -392,6 +405,7 @@ test "store vector elements via comptime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -441,6 +455,7 @@ test "store vector elements via runtime index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -485,6 +500,7 @@ test "vector comparison operators" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -532,6 +548,7 @@ test "vector division operators" { if (builtin.zig_backend == .stage2_llvm and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void { @@ -622,6 +639,7 @@ test "vector bitwise not operator" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void { @@ -653,6 +671,7 @@ test "vector shift operators" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTestShift(x: anytype, y: anytype) !void { @@ -743,6 +762,7 @@ test "vector reduce operation" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn testReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void { @@ -901,6 +921,7 @@ test "mask parameter of @shuffle is comptime scope" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .ssse3)) return error.SkipZigTest; @@ -927,6 +948,7 @@ test "saturating add" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -961,6 +983,7 @@ test "saturating subtraction" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -985,6 +1008,7 @@ test "saturating multiplication" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO: once #9660 has been solved, remove this line if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest; @@ -1013,6 +1037,7 @@ test "saturating shift-left" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1036,6 +1061,7 @@ test "multiplication-assignment operator with an array operand" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1056,6 +1082,7 @@ test "@addWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1103,6 +1130,7 @@ test "@subWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1134,6 +1162,7 @@ test "@mulWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1155,6 +1184,7 @@ test "@shlWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1198,6 +1228,7 @@ test "loading the second vector from a slice of vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @setRuntimeSafety(false); var small_bases = [2]@Vector(2, u8){ @@ -1214,6 +1245,7 @@ test "array of vectors is copied" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const Vec3 = @Vector(3, i32); var points = [_]Vec3{ @@ -1237,6 +1269,7 @@ test "byte vector initialized in inline function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.cpu.features.isEnabled(@intFromEnum(std.Target.x86.Feature.avx512f))) @@ -1306,6 +1339,7 @@ test "@intCast to u0" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var zeros = @Vector(2, u32){ 0, 0 }; _ = &zeros; @@ -1330,6 +1364,7 @@ test "array operands to shuffle are coerced to vectors" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const mask = [5]i32{ -1, 0, 1, 2, 3 }; @@ -1345,6 +1380,7 @@ test "load packed vector element" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: @Vector(2, u15) = .{ 1, 4 }; try expect((&x[0]).* == 1); @@ -1358,6 +1394,7 @@ test "store packed vector element" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var v = @Vector(4, u1){ 1, 1, 1, 1 }; try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v); @@ -1373,6 +1410,7 @@ test "store to vector in slice" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var v = [_]@Vector(3, f32){ .{ 1, 1, 1 }, @@ -1392,6 +1430,8 @@ test "store vector with memset" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) { switch (builtin.target.cpu.arch) { @@ -1437,6 +1477,7 @@ test "store vector with memset" { test "addition of vectors represented as strings" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const V = @Vector(3, u8); const foo: V = "foo".*; @@ -1450,6 +1491,7 @@ test "compare vectors with different element types" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: @Vector(2, u8) = .{ 1, 2 }; var b: @Vector(2, u9) = .{ 3, 0 }; @@ -1462,6 +1504,7 @@ test "vector pointer is indexable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const V = @Vector(2, u32); @@ -1502,6 +1545,7 @@ test "bitcast to vector with different child type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1530,7 +1574,6 @@ test "arithmetic on zero-length vectors" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO { @@ -1565,6 +1608,7 @@ test "@reduce on bool vector" { test "bitcast vector to array of smaller vectors" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const u8x32 = @Vector(32, u8); const u8x64 = @Vector(64, u8); diff --git a/test/behavior/void.zig b/test/behavior/void.zig index 42c57ca3a6..5c4215b870 100644 --- a/test/behavior/void.zig +++ b/test/behavior/void.zig @@ -20,6 +20,7 @@ test "compare void with void compile time known" { test "iterate over a void slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var j: usize = 0; for (times(10), 0..) |_, i| { @@ -36,6 +37,7 @@ test "void optional" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: ?void = {}; _ = &x; diff --git a/test/behavior/wasm.zig b/test/behavior/wasm.zig index c7d12be29d..2db3847f87 100644 --- a/test/behavior/wasm.zig +++ b/test/behavior/wasm.zig @@ -3,6 +3,8 @@ const expect = std.testing.expect; const builtin = @import("builtin"); test "memory size and grow" { + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + var prev = @wasmMemorySize(0); _ = &prev; try expect(prev == @wasmMemoryGrow(0, 1)); diff --git a/test/behavior/while.zig b/test/behavior/while.zig index 51ae8c5d98..e1e5ebbfb3 100644 --- a/test/behavior/while.zig +++ b/test/behavior/while.zig @@ -106,6 +106,7 @@ fn testBreakOuter() void { test "while copies its payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -144,6 +145,7 @@ fn runContinueAndBreakTest() !void { test "while with optional as condition" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; numbers_left = 10; var sum: i32 = 0; @@ -156,6 +158,7 @@ test "while with optional as condition" { test "while with optional as condition with else" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; numbers_left = 10; var sum: i32 = 0; @@ -172,6 +175,7 @@ test "while with optional as condition with else" { test "while with error union condition" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; numbers_left = 10; var sum: i32 = 0; @@ -204,6 +208,7 @@ test "while on optional with else result follow else prong" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const result = while (returnNull()) |value| { break value; @@ -215,6 +220,7 @@ test "while on optional with else result follow break prong" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const result = while (returnOptional(10)) |value| { break value; @@ -252,6 +258,7 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { test "while on error union with else result follow else prong" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const result = while (returnError()) |value| { break value; @@ -261,6 +268,7 @@ test "while on error union with else result follow else prong" { test "while on error union with else result follow break prong" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const result = while (returnSuccess(10)) |value| { break value; @@ -287,6 +295,7 @@ test "while optional 2 break statements and an else" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry(opt_t: ?bool, f: bool) !void { @@ -306,6 +315,7 @@ test "while error 2 break statements and an else" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn entry(opt_t: anyerror!bool, f: bool) !void { @@ -344,6 +354,7 @@ test "try terminating an infinite loop" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // Test coverage for https://github.com/ziglang/zig/issues/13546 const Foo = struct { @@ -371,6 +382,7 @@ test "while loop with comptime true condition needs no else block to return valu test "int returned from switch in while" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: u32 = 3; const val: usize = while (true) switch (x) { @@ -384,6 +396,7 @@ test "breaking from a loop in an if statement" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn retOpt() ?u32 { diff --git a/test/behavior/widening.zig b/test/behavior/widening.zig index c60bb23e3b..16f97550b5 100644 --- a/test/behavior/widening.zig +++ b/test/behavior/widening.zig @@ -8,6 +8,7 @@ test "integer widening" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u8 = 250; var b: u16 = a; @@ -31,6 +32,7 @@ test "implicit unsigned integer to signed integer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: u8 = 250; var b: i16 = a; @@ -44,6 +46,7 @@ test "float widening" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var a: f16 = 12.34; var b: f32 = a; @@ -64,6 +67,7 @@ test "float widening f16 to f128" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; var x: f16 = 12.34; var y: f128 = x; @@ -76,6 +80,7 @@ test "cast small unsigned to larger signed" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200)); try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999)); diff --git a/test/behavior/wrapping_arithmetic.zig b/test/behavior/wrapping_arithmetic.zig index 2733edad71..958be2f6f0 100644 --- a/test/behavior/wrapping_arithmetic.zig +++ b/test/behavior/wrapping_arithmetic.zig @@ -6,6 +6,7 @@ const expect = std.testing.expect; test "wrapping add" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -43,6 +44,7 @@ test "wrapping add" { test "wrapping subtraction" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -78,6 +80,7 @@ test "wrapping subtraction" { test "wrapping multiplication" { if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO: once #9660 has been solved, remove this line if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; diff --git a/test/cases/compile_errors/capture_by_ref_while.zig b/test/cases/compile_errors/capture_by_ref_while.zig index 916662c180..dcb7c23548 100644 --- a/test/cases/compile_errors/capture_by_ref_while.zig +++ b/test/cases/compile_errors/capture_by_ref_while.zig @@ -7,4 +7,4 @@ test { // target=native // // :2:25: error: unused capture -// :2:39: error: unused capture \ No newline at end of file +// :2:39: error: unused capture diff --git a/test/cases/compile_errors/switch_expression-missing_error_prong.zig b/test/cases/compile_errors/switch_expression-missing_error_prong.zig index ee28057c43..ec0c0ceb2f 100644 --- a/test/cases/compile_errors/switch_expression-missing_error_prong.zig +++ b/test/cases/compile_errors/switch_expression-missing_error_prong.zig @@ -1,4 +1,4 @@ -const Error = error { +const Error = error{ One, Two, Three, diff --git a/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig b/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig index a6bb48db17..9a56c17081 100644 --- a/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig +++ b/test/cases/compile_errors/switch_expression-multiple_else_prongs.zig @@ -5,14 +5,14 @@ fn f(x: u32) void { else => true, }; } -fn g(x: error{Foo, Bar, Baz}!u32) void { +fn g(x: error{ Foo, Bar, Baz }!u32) void { const value: bool = if (x) |_| true else |e| switch (e) { error.Foo => false, else => true, else => true, }; } -fn h(x: error{Foo, Bar, Baz}!u32) void { +fn h(x: error{ Foo, Bar, Baz }!u32) void { const value: u32 = x catch |e| switch (e) { error.Foo => 1, else => 2, diff --git a/test/cases/inherit_want_safety.zig b/test/cases/inherit_want_safety.zig index a0c79952b8..c9cd399df9 100644 --- a/test/cases/inherit_want_safety.zig +++ b/test/cases/inherit_want_safety.zig @@ -28,7 +28,7 @@ pub export fn entry() usize { } else |e| switch (e) { else => { u += 1; - } + }, } return u; } diff --git a/test/tests.zig b/test/tests.zig index 8affc41846..c0ef4a536a 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -435,6 +435,16 @@ const test_targets = blk: { // .use_llvm = true, //}, + .{ + .target = .{ + .cpu_arch = .riscv64, + .os_tag = .linux, + .abi = .musl, + }, + .use_llvm = false, + .use_lld = false, + }, + // https://github.com/ziglang/zig/issues/3340 //.{ // .target = .{ @@ -1019,6 +1029,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { test_target.use_llvm == false and mem.eql(u8, options.name, "std")) continue; + if (target.cpu.arch != .x86_64 and + test_target.use_llvm == false and mem.eql(u8, options.name, "c-import")) + continue; + if (target.cpu.arch == .x86_64 and target.os.tag == .windows and test_target.target.cpu_arch == null and test_target.optimize_mode != .Debug and mem.eql(u8, options.name, "std"))