diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 37c3c52604..56bbe28e0e 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -46,6 +46,10 @@ comptime { @export(log10, .{ .name = "log10", .linkage = .Strong }); @export(log10f, .{ .name = "log10f", .linkage = .Strong }); + + @export(ceil, .{ .name = "ceil", .linkage = .Strong }); + @export(ceilf, .{ .name = "ceilf", .linkage = .Strong }); + @export(ceill, .{ .name = "ceill", .linkage = .Strong }); } // Avoid dragging in the runtime safety mechanisms into this .o file, @@ -179,3 +183,18 @@ fn log10(a: f64) callconv(.C) f64 { fn log10f(a: f32) callconv(.C) f32 { return math.log10(a); } + +fn ceilf(x: f32) callconv(.C) f32 { + return math.ceil(x); +} + +fn ceil(x: f64) callconv(.C) f64 { + return math.ceil(x); +} + +fn ceill(x: c_longdouble) callconv(.C) c_longdouble { + if (!long_double_is_f128) { + @panic("TODO implement this"); + } + return math.ceil(x); +} diff --git a/lib/std/special/c_stage1.zig b/lib/std/special/c_stage1.zig index 8541162293..7549c65d59 100644 --- a/lib/std/special/c_stage1.zig +++ b/lib/std/special/c_stage1.zig @@ -613,19 +613,6 @@ export fn fmod(x: f64, y: f64) f64 { return generic_fmod(f64, x, y); } -export fn ceilf(x: f32) f32 { - return math.ceil(x); -} -export fn ceil(x: f64) f64 { - return math.ceil(x); -} -export fn ceill(x: c_longdouble) c_longdouble { - if (!long_double_is_f128) { - @panic("TODO implement this"); - } - return math.ceil(x); -} - export fn fmaf(a: f32, b: f32, c: f32) f32 { return math.fma(f32, a, b, c); } diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 3a5849b1a2..eac592359a 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -141,7 +141,10 @@ pub fn main2() anyerror!void { } }; } - if (builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_wasm) { + if (builtin.zig_backend == .stage2_llvm or + builtin.zig_backend == .stage2_wasm or + (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .macos)) + { const passed = builtin.test_functions.len - skipped - failed; const stderr = std.io.getStdErr(); writeInt(stderr, passed) catch {}; diff --git a/src/Liveness.zig b/src/Liveness.zig index 5a329d2a7a..e2671702c4 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -135,6 +135,42 @@ pub fn getCondBr(l: Liveness, inst: Air.Inst.Index) CondBrSlices { }; } +/// Indexed by case number as they appear in AIR. +/// Else is the last element. +pub const SwitchBrTable = struct { + deaths: []const []const Air.Inst.Index, +}; + +/// Caller owns the memory. +pub fn getSwitchBr(l: Liveness, gpa: Allocator, inst: Air.Inst.Index, cases_len: u32) Allocator.Error!SwitchBrTable { + var index: usize = l.special.get(inst) orelse return SwitchBrTable{ + .deaths = &.{}, + }; + const else_death_count = l.extra[index]; + index += 1; + + var deaths = std.ArrayList([]const Air.Inst.Index).init(gpa); + defer deaths.deinit(); + try deaths.ensureTotalCapacity(cases_len + 1); + + var case_i: u32 = 0; + while (case_i < cases_len - 1) : (case_i += 1) { + const case_death_count: u32 = l.extra[index]; + index += 1; + const case_deaths = l.extra[index..][0..case_death_count]; + index += case_death_count; + deaths.appendAssumeCapacity(case_deaths); + } + { + // Else + const else_deaths = l.extra[index..][0..else_death_count]; + deaths.appendAssumeCapacity(else_deaths); + } + return SwitchBrTable{ + .deaths = deaths.toOwnedSlice(), + }; +} + pub fn deinit(l: *Liveness, gpa: Allocator) void { gpa.free(l.tomb_bits); gpa.free(l.extra); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 5cd74e9a6e..e59161a766 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -49,6 +49,9 @@ arg_index: u32, src_loc: Module.SrcLoc, stack_align: u32, +ret_backpatch: ?Mir.Inst.Index = null, +compare_flags_inst: ?Air.Inst.Index = null, + /// MIR Instructions mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, /// MIR extra data @@ -470,6 +473,20 @@ fn gen(self: *Self) InnerError!void { }; inline for (callee_preserved_regs) |reg, i| { if (self.register_manager.isRegAllocated(reg)) { + if (self.ret_backpatch) |inst| { + if (reg.to64() == .rdi) { + const ops = Mir.Ops.decode(self.mir_instructions.items(.ops)[inst]); + self.mir_instructions.set(inst, Mir.Inst{ + .tag = .mov, + .ops = (Mir.Ops{ + .reg1 = ops.reg1, + .reg2 = .rbp, + .flags = 0b01, + }).encode(), + .data = .{ .imm = @bitCast(u32, -@intCast(i32, self.max_end_stack + 8)) }, + }); + } + } data.regs |= 1 << @intCast(u5, i); self.max_end_stack += 8; } @@ -758,6 +775,9 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { const canon_reg = reg.to64(); self.register_manager.freeReg(canon_reg); }, + .compare_flags_signed, .compare_flags_unsigned => { + self.compare_flags_inst = null; + }, else => {}, // TODO process stack allocation death } } @@ -870,7 +890,23 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void assert(reg.to64() == reg_mcv.register.to64()); 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.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); + try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); +} + +pub fn spillCompareFlagsIfOccupied(self: *Self) !void { + if (self.compare_flags_inst) |inst_to_save| { + const mcv = self.getResolvedInstValue(inst_to_save); + assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned); + + const new_mcv = try self.allocRegOrMem(inst_to_save, true); + try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); + log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); + + const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; + try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); + + self.compare_flags_inst = null; + } } /// Copies a value to a register without tracking the register. The register is not considered @@ -925,8 +961,6 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { const operand = try self.resolveInst(ty_op.operand); const info_a = operand_ty.intInfo(self.target.*); const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); - if (info_a.signedness != info_b.signedness) - return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); const operand_abi_size = operand_ty.abiSize(self.target.*); const dest_ty = self.air.typeOfIndex(inst); @@ -1058,10 +1092,44 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { fn airMin(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) - .dead - else - return self.fail("TODO implement min for {}", .{self.target.cpu.arch}); + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); + } + + const ty = self.air.typeOfIndex(inst); + if (ty.zigTypeTag() != .Int) { + return self.fail("TODO implement min for type {}", .{ty}); + } + const signedness = ty.intInfo(self.target.*).signedness; + const result: MCValue = result: { + // TODO improve by checking if any operand can be reused. + // TODO audit register allocation + const lhs = try self.resolveInst(bin_op.lhs); + lhs.freezeIfRegister(&self.register_manager); + defer lhs.unfreezeIfRegister(&self.register_manager); + + const lhs_reg = try self.copyToTmpRegister(ty, lhs); + self.register_manager.freezeRegs(&.{lhs_reg}); + defer self.register_manager.unfreezeRegs(&.{lhs_reg}); + + const rhs_mcv = try self.limitImmediateType(bin_op.rhs, i32); + rhs_mcv.freezeIfRegister(&self.register_manager); + defer rhs_mcv.unfreezeIfRegister(&self.register_manager); + + try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); + + const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); + _ = try self.addInst(.{ + .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below, + .ops = (Mir.Ops{ + .reg1 = dst_mcv.register, + .reg2 = lhs_reg, + }).encode(), + .data = undefined, + }); + + break :result dst_mcv; + }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -1081,9 +1149,6 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r const offset = try self.resolveInst(op_rhs); const offset_ty = self.air.typeOf(op_rhs); - ptr.freezeIfRegister(&self.register_manager); - defer ptr.unfreezeIfRegister(&self.register_manager); - offset.freezeIfRegister(&self.register_manager); defer offset.unfreezeIfRegister(&self.register_manager); @@ -1091,9 +1156,12 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r if (self.reuseOperand(inst, op_lhs, 0, ptr)) { if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; } - break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, ptr); + break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, ptr) }; }; + dst_mcv.freezeIfRegister(&self.register_manager); + defer dst_mcv.unfreezeIfRegister(&self.register_manager); + const offset_mcv = blk: { if (self.reuseOperand(inst, op_rhs, 1, offset)) { if (offset.isRegister()) break :blk offset; @@ -1101,6 +1169,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) }; }; + offset_mcv.freezeIfRegister(&self.register_manager); + defer offset_mcv.unfreezeIfRegister(&self.register_manager); + try self.genIMulOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); const tag = self.air.instructions.items(.tag)[inst]; @@ -1145,8 +1216,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { const len_ty = self.air.typeOf(bin_op.rhs); const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); - try self.genSetStack(ptr_ty, stack_offset, ptr); - try self.genSetStack(len_ty, stack_offset - 8, len); + try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); + try self.genSetStack(len_ty, stack_offset - 8, len, .{}); const result = MCValue{ .stack_offset = stack_offset }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); @@ -1179,12 +1250,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } +fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { + const dst_ty = self.air.typeOfIndex(inst); + const lhs = try self.resolveInst(op_lhs); + const rhs = try self.resolveInst(op_rhs); + + rhs.freezeIfRegister(&self.register_manager); + defer rhs.unfreezeIfRegister(&self.register_manager); + + const dst_mcv = blk: { + if (self.reuseOperand(inst, op_lhs, 0, lhs)) { + if (lhs.isMemory() or lhs.isRegister()) break :blk lhs; + } + break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); + }; + + dst_mcv.freezeIfRegister(&self.register_manager); + defer dst_mcv.unfreezeIfRegister(&self.register_manager); + + const rhs_mcv = blk: { + if (rhs.isRegister()) break :blk rhs; + break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; + }; + + rhs_mcv.freezeIfRegister(&self.register_manager); + defer rhs_mcv.unfreezeIfRegister(&self.register_manager); + + try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv); + + return dst_mcv; +} + fn airSub(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else - try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); + try self.genSubOp(inst, bin_op.lhs, bin_op.rhs); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -1523,11 +1625,58 @@ fn airXor(self: *Self, inst: Air.Inst.Index) !void { fn airShl(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) - .dead - else - return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); + } + + const ty = self.air.typeOfIndex(inst); + const tag = self.air.instructions.items(.tag)[inst]; + switch (tag) { + .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty }), + .shl => {}, + else => unreachable, + } + + if (ty.zigTypeTag() != .Int) { + return self.fail("TODO implement .shl for type {}", .{ty}); + } + if (ty.abiSize(self.target.*) > 8) { + return self.fail("TODO implement .shl for integers larger than 8 bytes", .{}); + } + + // TODO look into reusing the operands + // TODO audit register allocation mechanics + const shift = try self.resolveInst(bin_op.rhs); + const shift_ty = self.air.typeOf(bin_op.rhs); + + blk: { + switch (shift) { + .register => |reg| { + if (reg.to64() == .rcx) break :blk; + }, + else => {}, + } + try self.register_manager.getReg(.rcx, null); + try self.genSetReg(shift_ty, .rcx, shift); + } + self.register_manager.freezeRegs(&.{.rcx}); + defer self.register_manager.unfreezeRegs(&.{.rcx}); + + const value = try self.resolveInst(bin_op.lhs); + value.freezeIfRegister(&self.register_manager); + defer value.unfreezeIfRegister(&self.register_manager); + + const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value); + _ = try self.addInst(.{ + .tag = .sal, + .ops = (Mir.Ops{ + .reg1 = dst_mcv.register, + .flags = 0b01, + }).encode(), + .data = undefined, + }); + + return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { @@ -1580,23 +1729,44 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const err_union_ty = self.air.typeOf(ty_op.operand); - const payload_ty = err_union_ty.errorUnionPayload(); - const mcv = try self.resolveInst(ty_op.operand); - if (!payload_ty.hasRuntimeBits()) break :result mcv; - return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + } + const err_union_ty = self.air.typeOf(ty_op.operand); + const payload_ty = err_union_ty.errorUnionPayload(); + const operand = try self.resolveInst(ty_op.operand); + const result: MCValue = result: { + if (!payload_ty.hasRuntimeBits()) break :result operand; + switch (operand) { + .stack_offset => |off| { + break :result MCValue{ .stack_offset = off }; + }, + 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)[inst].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const err_union_ty = self.air.typeOf(ty_op.operand); - const payload_ty = err_union_ty.errorUnionPayload(); + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + } + const err_union_ty = self.air.typeOf(ty_op.operand); + const payload_ty = err_union_ty.errorUnionPayload(); + const result: MCValue = result: { if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; - return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); + + const operand = try self.resolveInst(ty_op.operand); + const err_ty = err_union_ty.errorUnionSet(); + const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); + switch (operand) { + .stack_offset => |off| { + const offset = off - @intCast(i32, err_abi_size); + break :result MCValue{ .stack_offset = offset }; + }, + else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}), + } }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -1647,24 +1817,47 @@ 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)[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}); - return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + } + const error_union_ty = self.air.getRefType(ty_op.ty); + const error_ty = error_union_ty.errorUnionSet(); + const payload_ty = error_union_ty.errorUnionPayload(); + const operand = try self.resolveInst(ty_op.operand); + assert(payload_ty.hasRuntimeBits()); + + const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); + const abi_align = error_union_ty.abiAlignment(self.target.*); + const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*)); + const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); + try self.genSetStack(error_ty, stack_offset, .{ .immediate = 0 }, .{}); + try self.genSetStack(payload_ty, stack_offset - @intCast(i32, err_abi_size), operand, .{}); + + return self.finishAir(inst, .{ .stack_offset = stack_offset }, .{ ty_op.operand, .none, .none }); } /// E to E!T fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const error_union_ty = self.air.getRefType(ty_op.ty); - const payload_ty = error_union_ty.errorUnionPayload(); - const mcv = try self.resolveInst(ty_op.operand); - if (!payload_ty.hasRuntimeBits()) break :result mcv; + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); + } + const error_union_ty = self.air.getRefType(ty_op.ty); + const error_ty = error_union_ty.errorUnionSet(); + const payload_ty = error_union_ty.errorUnionPayload(); + const err = try self.resolveInst(ty_op.operand); + const result: MCValue = result: { + if (!payload_ty.hasRuntimeBits()) break :result err; - return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); + const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); + const abi_align = error_union_ty.abiAlignment(self.target.*); + const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*)); + const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); + try self.genSetStack(error_ty, stack_offset, err, .{}); + try self.genSetStack(payload_ty, stack_offset - @intCast(i32, err_abi_size), .undef, .{}); + break :result MCValue{ .stack_offset = stack_offset }; }; + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -1824,7 +2017,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { @intCast(u32, array_ty.abiSize(self.target.*)), array_ty.abiAlignment(self.target.*), )); - try self.genSetStack(array_ty, off, array); + try self.genSetStack(array_ty, off, array, .{}); break :inner off; }, .stack_offset => |off| { @@ -2057,10 +2250,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo if (abi_size <= 8) { const tmp_reg = try self.register_manager.allocReg(null); try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); - return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); + return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{}); } - try self.genInlineMemcpy(off, .rbp, elem_ty, ptr); + try self.genInlineMemcpy(off, elem_ty, ptr, .{}); }, else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), } @@ -2155,7 +2348,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type try self.store(.{ .register = reg }, value, ptr_ty, value_ty); }, .ptr_stack_offset => |off| { - try self.genSetStack(value_ty, off, value); + try self.genSetStack(value_ty, off, value, .{}); }, .ptr_embedded_in_code => |off| { try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value); @@ -2590,6 +2783,8 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC .memory, .got_load, .direct_load, + .compare_flags_signed, + .compare_flags_unsigned, => { assert(abi_size <= 8); self.register_manager.freezeRegs(&.{dst_reg}); @@ -2611,12 +2806,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC .data = .{ .imm = @bitCast(u32, -off) }, }); }, - .compare_flags_unsigned => { - return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{}); - }, - .compare_flags_signed => { - return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{}); - }, } }, .stack_offset => |off| { @@ -2629,7 +2818,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC switch (src_mcv) { .none => unreachable, - .undef => return self.genSetStack(dst_ty, off, .undef), + .undef => return self.genSetStack(dst_ty, off, .undef, .{}), .dead, .unreach => unreachable, .ptr_stack_offset => unreachable, .ptr_embedded_in_code => unreachable, @@ -2772,7 +2961,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! .stack_offset => |off| { switch (src_mcv) { .none => unreachable, - .undef => return self.genSetStack(dst_ty, off, .undef), + .undef => return self.genSetStack(dst_ty, off, .undef, .{}), .dead, .unreach => unreachable, .ptr_stack_offset => unreachable, .ptr_embedded_in_code => unreachable, @@ -2790,7 +2979,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! .data = undefined, }); // copy dst_reg back out - return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg }); + return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg }, .{}); }, .immediate => |imm| { _ = imm; @@ -2888,6 +3077,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { var info = try self.resolveCallingConventionValues(fn_ty); defer info.deinit(self); + try self.spillCompareFlagsIfOccupied(); + + if (info.return_value == .stack_offset) { + const ret_ty = fn_ty.fnReturnType(); + const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); + const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); + const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); + + try self.register_manager.getReg(.rdi, inst); + try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); + + info.return_value.stack_offset = stack_offset; + } + for (args) |arg, arg_i| { const mc_arg = info.args[arg_i]; const arg_ty = self.air.typeOf(arg); @@ -3099,9 +3302,33 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { return bt.finishAir(result); } -fn ret(self: *Self, mcv: MCValue) !void { +fn airRet(self: *Self, inst: Air.Inst.Index) !void { + const un_op = self.air.instructions.items(.data)[inst].un_op; + const operand = try self.resolveInst(un_op); const ret_ty = self.fn_type.fnReturnType(); - try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); + switch (self.ret_mcv) { + .stack_offset => { + // TODO audit register allocation! + self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); + defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); + const reg = try self.register_manager.allocReg(null); + self.ret_backpatch = try self.addInst(.{ + .tag = .mov, + .ops = (Mir.Ops{ + .reg1 = reg, + .reg2 = .rdi, + }).encode(), + .data = undefined, + }); + try self.genSetStack(ret_ty, 0, operand, .{ + .source_stack_base = .rbp, + .dest_stack_base = reg, + }); + }, + else => { + try self.setRegOrMem(ret_ty, self.ret_mcv, operand); + }, + } // TODO when implementing defer, this will need to jump to the appropriate defer expression. // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction // which is available if the jump is 127 bytes or less forward. @@ -3113,21 +3340,49 @@ fn ret(self: *Self, mcv: MCValue) !void { .data = .{ .inst = undefined }, }); try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); -} - -fn airRet(self: *Self, inst: Air.Inst.Index) !void { - const un_op = self.air.instructions.items(.data)[inst].un_op; - const operand = try self.resolveInst(un_op); - try self.ret(operand); return self.finishAir(inst, .dead, .{ un_op, .none, .none }); } fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; const ptr = try self.resolveInst(un_op); - // we can reuse self.ret_mcv because it just gets returned - try self.load(self.ret_mcv, ptr, self.air.typeOf(un_op)); - try self.ret(self.ret_mcv); + const ptr_ty = self.air.typeOf(un_op); + const elem_ty = ptr_ty.elemType(); + switch (self.ret_mcv) { + .stack_offset => { + // TODO audit register allocation! + self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); + defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); + const reg = try self.register_manager.allocReg(null); + self.ret_backpatch = try self.addInst(.{ + .tag = .mov, + .ops = (Mir.Ops{ + .reg1 = reg, + .reg2 = .rdi, + }).encode(), + .data = undefined, + }); + try self.genInlineMemcpy(0, elem_ty, ptr, .{ + .source_stack_base = .rbp, + .dest_stack_base = reg, + }); + }, + else => { + try self.load(self.ret_mcv, ptr, ptr_ty); + try self.setRegOrMem(elem_ty, self.ret_mcv, self.ret_mcv); + }, + } + // TODO when implementing defer, this will need to jump to the appropriate defer expression. + // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction + // which is available if the jump is 127 bytes or less forward. + const jmp_reloc = try self.addInst(.{ + .tag = .jmp, + .ops = (Mir.Ops{ + .flags = 0b00, + }).encode(), + .data = .{ .inst = undefined }, + }); + try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); return self.finishAir(inst, .dead, .{ un_op, .none, .none }); } @@ -3147,16 +3402,24 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { break :blk ty.intInfo(self.target.*).signedness; }; - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); + try self.spillCompareFlagsIfOccupied(); + self.compare_flags_inst = inst; + const result: MCValue = result: { // There are 2 operands, destination and source. // Either one, but not both, can be a memory operand. // Source operand can be an immediate, 8 bits or 32 bits. - const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory())) - MCValue{ .register = try self.copyToTmpRegister(ty, lhs) } - else - lhs; + // TODO look into reusing the operand + const lhs = try self.resolveInst(bin_op.lhs); + lhs.freezeIfRegister(&self.register_manager); + defer lhs.unfreezeIfRegister(&self.register_manager); + + const dst_reg = try self.copyToTmpRegister(ty, lhs); + self.register_manager.freezeRegs(&.{dst_reg}); + defer self.register_manager.unfreezeRegs(&.{dst_reg}); + + const dst_mcv = MCValue{ .register = dst_reg }; + // This instruction supports only signed 32-bit immediates at most. const src_mcv = try self.limitImmediateType(bin_op.rhs, i32); @@ -3166,6 +3429,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { .unsigned => MCValue{ .compare_flags_unsigned = op }, }; }; + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -3213,6 +3477,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { }); }, .register => |reg| { + try self.spillCompareFlagsIfOccupied(); _ = try self.addInst(.{ .tag = .@"test", .ops = (Mir.Ops{ @@ -3229,19 +3494,15 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { .data = .{ .inst = undefined }, }); }, - .immediate => { + .immediate, + .stack_offset, + => { + try self.spillCompareFlagsIfOccupied(); if (abi_size <= 8) { const reg = try self.copyToTmpRegister(ty, mcv); return self.genCondBrMir(ty, .{ .register = reg }); } - return self.fail("TODO implement condbr when condition is immediate larger than 4 bytes", .{}); - }, - .stack_offset => { - if (abi_size <= 8) { - const reg = try self.copyToTmpRegister(ty, mcv); - return self.genCondBrMir(ty, .{ .register = reg }); - } - return self.fail("TODO implement condbr when condition is stack offset with abi larger than 8 bytes", .{}); + return self.fail("TODO implement condbr when condition is {} with abi larger than 8 bytes", .{mcv}); }, else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}), } @@ -3258,9 +3519,23 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { const reloc = try self.genCondBrMir(cond_ty, cond); + // 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 + // TODO I need investigate how to make this work without removing + // an assertion from getResolvedInstValue() + if (self.liveness.operandDies(inst, 0)) { + const op_int = @enumToInt(pl_op.operand); + if (op_int >= Air.Inst.Ref.typed_value_map.len) { + const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); + self.processDeath(op_index); + } + } + // Capture the state of register and stack allocation state so that we can revert to it. const parent_next_stack_offset = self.next_stack_offset; const parent_free_registers = self.register_manager.free_registers; + const parent_compare_flags_inst = self.compare_flags_inst; var parent_stack = try self.stack.clone(self.gpa); defer parent_stack.deinit(self.gpa); const parent_registers = self.register_manager.registers; @@ -3282,6 +3557,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { defer saved_then_branch.deinit(self.gpa); self.register_manager.registers = parent_registers; + self.compare_flags_inst = parent_compare_flags_inst; self.stack.deinit(self.gpa); self.stack = parent_stack; @@ -3352,6 +3628,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { // We already deleted the items from this table that matched the else_branch. // So these are all instructions that are only overridden in the then branch. parent_branch.inst_table.putAssumeCapacity(then_key, then_value); + log.debug("then_value = {}", .{then_value}); if (then_value == .dead) continue; const parent_mcv = blk: { @@ -3376,23 +3653,31 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); } -fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { +fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { + try self.spillCompareFlagsIfOccupied(); + self.compare_flags_inst = inst; + try self.genBinMathOpMir(.cmp, ty, operand, MCValue{ .immediate = 0 }); return MCValue{ .compare_flags_unsigned = .eq }; } -fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { - const is_null_res = try self.isNull(ty, operand); +fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { + const is_null_res = try self.isNull(inst, ty, operand); assert(is_null_res.compare_flags_unsigned == .eq); return MCValue{ .compare_flags_unsigned = .neq }; } -fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { +fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { const err_type = ty.errorUnionSet(); const payload_type = ty.errorUnionPayload(); if (!err_type.hasRuntimeBits()) { return MCValue{ .immediate = 0 }; // always false - } else if (!payload_type.hasRuntimeBits()) { + } + + try self.spillCompareFlagsIfOccupied(); + self.compare_flags_inst = inst; + + if (!payload_type.hasRuntimeBits()) { if (err_type.abiSize(self.target.*) <= 8) { try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); return MCValue{ .compare_flags_unsigned = .gt }; @@ -3400,12 +3685,13 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { return self.fail("TODO isErr for errors with size larger than register size", .{}); } } else { - return self.fail("TODO isErr for non-empty payloads", .{}); + try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); + return MCValue{ .compare_flags_unsigned = .gt }; } } -fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { - const is_err_res = try self.isErr(ty, operand); +fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { + const is_err_res = try self.isErr(inst, ty, operand); switch (is_err_res) { .compare_flags_unsigned => |op| { assert(op == .gt); @@ -3424,7 +3710,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(un_op); const ty = self.air.typeOf(un_op); - break :result try self.isNull(ty, operand); + break :result try self.isNull(inst, ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3445,7 +3731,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { }; const ptr_ty = self.air.typeOf(un_op); try self.load(operand, operand_ptr, ptr_ty); - break :result try self.isNull(ptr_ty.elemType(), operand); + break :result try self.isNull(inst, ptr_ty.elemType(), operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3455,7 +3741,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(un_op); const ty = self.air.typeOf(un_op); - break :result try self.isNonNull(ty, operand); + break :result try self.isNonNull(inst, ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3476,7 +3762,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { }; const ptr_ty = self.air.typeOf(un_op); try self.load(operand, operand_ptr, ptr_ty); - break :result try self.isNonNull(ptr_ty.elemType(), operand); + break :result try self.isNonNull(inst, ptr_ty.elemType(), operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3486,7 +3772,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(un_op); const ty = self.air.typeOf(un_op); - break :result try self.isErr(ty, operand); + break :result try self.isErr(inst, ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3507,7 +3793,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { }; const ptr_ty = self.air.typeOf(un_op); try self.load(operand, operand_ptr, ptr_ty); - break :result try self.isErr(ptr_ty.elemType(), operand); + break :result try self.isErr(inst, ptr_ty.elemType(), operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3517,7 +3803,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(un_op); const ty = self.air.typeOf(un_op); - break :result try self.isNonErr(ty, operand); + break :result try self.isNonErr(inst, ty, operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3538,7 +3824,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { }; const ptr_ty = self.air.typeOf(un_op); try self.load(operand, operand_ptr, ptr_ty); - break :result try self.isNonErr(ptr_ty.elemType(), operand); + break :result try self.isNonErr(inst, ptr_ty.elemType(), operand); }; return self.finishAir(inst, result, .{ un_op, .none, .none }); } @@ -3584,12 +3870,185 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ .none, .none, .none }); } +fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u32 { + const abi_size = @intCast(u32, ty.abiSize(self.target.*)); + switch (condition) { + .none => unreachable, + .undef => unreachable, + .dead, .unreach => unreachable, + .compare_flags_signed => unreachable, + .compare_flags_unsigned => unreachable, + .register => |cond_reg| { + try self.spillCompareFlagsIfOccupied(); + + self.register_manager.freezeRegs(&.{cond_reg}); + defer self.register_manager.unfreezeRegs(&.{cond_reg}); + + switch (case) { + .none => unreachable, + .undef => unreachable, + .dead, .unreach => unreachable, + .immediate => |imm| { + _ = try self.addInst(.{ + .tag = .@"test", + .ops = (Mir.Ops{ + .reg1 = registerAlias(cond_reg, abi_size), + }).encode(), + .data = .{ .imm = @intCast(u32, imm) }, + }); + return self.addInst(.{ + .tag = .cond_jmp_eq_ne, + .ops = (Mir.Ops{ + .flags = 0b00, + }).encode(), + .data = .{ .inst = undefined }, + }); + }, + .register => |reg| { + _ = try self.addInst(.{ + .tag = .@"test", + .ops = (Mir.Ops{ + .reg1 = registerAlias(cond_reg, abi_size), + .reg2 = registerAlias(reg, abi_size), + }).encode(), + .data = undefined, + }); + return self.addInst(.{ + .tag = .cond_jmp_eq_ne, + .ops = (Mir.Ops{ + .flags = 0b00, + }).encode(), + .data = .{ .inst = undefined }, + }); + }, + .stack_offset => { + if (abi_size <= 8) { + const reg = try self.copyToTmpRegister(ty, case); + return self.genCondSwitchMir(ty, condition, .{ .register = reg }); + } + + return self.fail("TODO implement switch mir when case is stack offset with abi larger than 8 bytes", .{}); + }, + else => { + return self.fail("TODO implement switch mir when case is {}", .{case}); + }, + } + }, + .stack_offset => { + try self.spillCompareFlagsIfOccupied(); + + if (abi_size <= 8) { + const reg = try self.copyToTmpRegister(ty, condition); + self.register_manager.freezeRegs(&.{reg}); + defer self.register_manager.unfreezeRegs(&.{reg}); + return self.genCondSwitchMir(ty, .{ .register = reg }, case); + } + + return self.fail("TODO implement switch mir when condition is stack offset with abi larger than 8 bytes", .{}); + }, + else => { + return self.fail("TODO implemenent switch mir when condition is {}", .{condition}); + }, + } +} + fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[inst].pl_op; - const condition = pl_op.operand; - _ = condition; - return self.fail("TODO airSwitch for {}", .{self.target.cpu.arch}); - // return self.finishAir(inst, .dead, .{ condition, .none, .none }); + const condition = try self.resolveInst(pl_op.operand); + const condition_ty = self.air.typeOf(pl_op.operand); + const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); + var extra_index: usize = switch_br.end; + var case_i: u32 = 0; + const liveness = try self.liveness.getSwitchBr( + self.gpa, + inst, + switch_br.data.cases_len + 1, + ); + defer self.gpa.free(liveness.deaths); + + while (case_i < switch_br.data.cases_len) : (case_i += 1) { + const case = self.air.extraData(Air.SwitchBr.Case, extra_index); + const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); + const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; + extra_index = case.end + items.len + case_body.len; + + var relocs = try self.gpa.alloc(u32, items.len); + defer self.gpa.free(relocs); + + for (items) |item, item_i| { + const item_mcv = try self.resolveInst(item); + relocs[item_i] = try self.genCondSwitchMir(condition_ty, condition, item_mcv); + } + + // 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 + // TODO I need investigate how to make this work without removing + // an assertion from getResolvedInstValue() + if (self.liveness.operandDies(inst, 0)) { + const op_int = @enumToInt(pl_op.operand); + if (op_int >= Air.Inst.Ref.typed_value_map.len) { + const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); + self.processDeath(op_index); + } + } + + // Capture the state of register and stack allocation state so that we can revert to it. + const parent_next_stack_offset = self.next_stack_offset; + const parent_free_registers = self.register_manager.free_registers; + const parent_compare_flags_inst = self.compare_flags_inst; + var parent_stack = try self.stack.clone(self.gpa); + defer parent_stack.deinit(self.gpa); + const parent_registers = self.register_manager.registers; + + try self.branch_stack.append(.{}); + errdefer { + _ = self.branch_stack.pop(); + } + + try self.ensureProcessDeathCapacity(liveness.deaths[case_i].len); + for (liveness.deaths[case_i]) |operand| { + self.processDeath(operand); + } + + try self.genBody(case_body); + + // Revert to the previous register and stack allocation state. + var saved_case_branch = self.branch_stack.pop(); + defer saved_case_branch.deinit(self.gpa); + + self.register_manager.registers = parent_registers; + self.compare_flags_inst = parent_compare_flags_inst; + self.stack.deinit(self.gpa); + self.stack = parent_stack; + parent_stack = .{}; + + self.next_stack_offset = parent_next_stack_offset; + self.register_manager.free_registers = parent_free_registers; + + for (relocs) |reloc| { + try self.performReloc(reloc); + } + } + + if (switch_br.data.else_body_len > 0) { + const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; + try self.branch_stack.append(.{}); + defer self.branch_stack.pop().deinit(self.gpa); + + const else_deaths = liveness.deaths.len - 1; + try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len); + for (liveness.deaths[else_deaths]) |operand| { + self.processDeath(operand); + } + + try self.genBody(else_body); + + // TODO consolidate returned MCValues between prongs and else branch like we do + // in airCondBr. + } + + return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); } fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { @@ -3628,7 +4087,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { block_data.mcv = switch (operand_mcv) { .none, .dead, .unreach => unreachable, .register, .stack_offset, .memory => operand_mcv, - .immediate => blk: { + .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: { const new_mcv = try self.allocRegOrMem(block, true); try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); break :blk new_mcv; @@ -3828,7 +4287,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { .none => return, .immediate => unreachable, .register => |reg| return self.genSetReg(ty, reg, val), - .stack_offset => |off| return self.genSetStack(ty, off, val), + .stack_offset => |off| return self.genSetStack(ty, off, val, .{}), .memory => { return self.fail("TODO implement setRegOrMem for memory", .{}); }, @@ -3849,7 +4308,9 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE const reg = try self.copyToTmpRegister(ty, mcv); return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); } - try self.genInlineMemset(stack_offset, .rsp, ty, .{ .immediate = 0xaa }); + try self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, .{ + .dest_stack_base = .rsp, + }); }, .compare_flags_unsigned, .compare_flags_signed, @@ -3904,7 +4365,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); } - try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv); + try self.genInlineMemcpy(stack_offset, ty, mcv, .{ + .source_stack_base = .rbp, + .dest_stack_base = .rsp, + }); }, .register => |reg| { _ = try self.addInst(.{ @@ -3927,12 +4391,15 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); } - try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv); + try self.genInlineMemcpy(stack_offset, ty, mcv, .{ + .source_stack_base = .rbp, + .dest_stack_base = .rsp, + }); }, } } -fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void { +fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void { const abi_size = ty.abiSize(self.target.*); switch (mcv) { .dead => unreachable, @@ -3943,23 +4410,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro return; // The already existing value will do just fine. // TODO Upgrade this to a memset call when we have that available. switch (ty.abiSize(self.target.*)) { - 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), - 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), - 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), - 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), - else => return self.genInlineMemset(stack_offset, .rbp, ty, .{ .immediate = 0xaa }), + 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }, opts), + 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }, opts), + 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }, opts), + 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), + else => return self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, opts), } }, .compare_flags_unsigned, .compare_flags_signed, => { const reg = try self.copyToTmpRegister(ty, mcv); - return self.genSetStack(ty, stack_offset, .{ .register = reg }); + return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts); }, .immediate => |x_big| { - if (stack_offset > 128) { - return self.fail("TODO implement set stack variable with large stack offset", .{}); - } + const base_reg = opts.dest_stack_base orelse .rbp; switch (abi_size) { 1, 2, 4 => { const payload = try self.addExtra(Mir.ImmPair{ @@ -3969,7 +4434,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro _ = try self.addInst(.{ .tag = .mov_mem_imm, .ops = (Mir.Ops{ - .reg1 = .rbp, + .reg1 = base_reg, .flags = switch (abi_size) { 1 => 0b00, 2 => 0b01, @@ -3991,7 +4456,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro _ = try self.addInst(.{ .tag = .mov_mem_imm, .ops = (Mir.Ops{ - .reg1 = .rbp, + .reg1 = base_reg, .flags = 0b10, }).encode(), .data = .{ .payload = payload }, @@ -4005,7 +4470,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro _ = try self.addInst(.{ .tag = .mov_mem_imm, .ops = (Mir.Ops{ - .reg1 = .rbp, + .reg1 = base_reg, .flags = 0b10, }).encode(), .data = .{ .payload = payload }, @@ -4022,6 +4487,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro return self.fail("stack offset too large", .{}); } + const base_reg = opts.dest_stack_base orelse .rbp; const is_power_of_two = (abi_size % 2) == 0; if (!is_power_of_two) { self.register_manager.freezeRegs(&.{reg}); @@ -4037,7 +4503,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro _ = try self.addInst(.{ .tag = .mov, .ops = (Mir.Ops{ - .reg1 = .rbp, + .reg1 = base_reg, .reg2 = registerAlias(tmp_reg, closest_power_of_two), .flags = 0b10, }).encode(), @@ -4062,7 +4528,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro _ = try self.addInst(.{ .tag = .mov, .ops = (Mir.Ops{ - .reg1 = .rbp, + .reg1 = base_reg, .reg2 = registerAlias(reg, @intCast(u32, abi_size)), .flags = 0b10, }).encode(), @@ -4077,14 +4543,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro => { if (abi_size <= 8) { const reg = try self.copyToTmpRegister(ty, mcv); - return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); } - try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv); + try self.genInlineMemcpy(stack_offset, ty, mcv, opts); }, .ptr_stack_offset => { const reg = try self.copyToTmpRegister(ty, mcv); - return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); }, .stack_offset => |off| { if (stack_offset == off) { @@ -4094,22 +4560,35 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro if (abi_size <= 8) { const reg = try self.copyToTmpRegister(ty, mcv); - return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); } - try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv); + try self.genInlineMemcpy(stack_offset, ty, mcv, opts); }, } } -fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void { +const InlineMemcpyOpts = struct { + source_stack_base: ?Register = null, + dest_stack_base: ?Register = null, +}; + +fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: InlineMemcpyOpts) InnerError!void { const abi_size = ty.abiSize(self.target.*); + // TODO this is wrong. We should check first if any of the operands is in `.rax` or `.rcx` before + // spilling. Consolidate with other TODOs regarding register allocation mechanics. try self.register_manager.getReg(.rax, null); try self.register_manager.getReg(.rcx, null); - self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp }); - defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp }); + self.register_manager.freezeRegs(&.{ .rax, .rcx }); + defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); + + if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); + defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); + + if (opts.dest_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); + defer if (opts.dest_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); const addr_reg: Register = blk: { switch (val) { @@ -4119,13 +4598,13 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type => { break :blk try self.loadMemPtrIntoRegister(Type.usize, val); }, - .stack_offset => |off| { + .ptr_stack_offset, .stack_offset => |off| { const addr_reg = (try self.register_manager.allocReg(null)).to64(); _ = try self.addInst(.{ .tag = .lea, .ops = (Mir.Ops{ .reg1 = addr_reg, - .reg2 = .rbp, + .reg2 = opts.source_stack_base orelse .rbp, }).encode(), .data = .{ .imm = @bitCast(u32, -off) }, }); @@ -4207,7 +4686,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type _ = try self.addInst(.{ .tag = .mov_scale_dst, .ops = (Mir.Ops{ - .reg1 = stack_reg, + .reg1 = opts.dest_stack_base orelse .rbp, .reg2 = tmp_reg.to8(), }).encode(), .data = .{ .imm = @bitCast(u32, -stack_offset) }, @@ -4254,9 +4733,9 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type fn genInlineMemset( self: *Self, stack_offset: i32, - stack_register: Register, ty: Type, value: MCValue, + opts: InlineMemcpyOpts, ) InnerError!void { try self.register_manager.getReg(.rax, null); @@ -4321,7 +4800,7 @@ fn genInlineMemset( _ = try self.addInst(.{ .tag = .mov_mem_index_imm, .ops = (Mir.Ops{ - .reg1 = stack_register.to64(), + .reg1 = opts.dest_stack_base orelse .rbp, }).encode(), .data = .{ .payload = payload }, }); @@ -4653,8 +5132,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { const array_len = array_ty.arrayLenIncludingSentinel(); const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); - try self.genSetStack(ptr_ty, stack_offset, ptr); - try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }); + try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); + try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }, .{}); break :blk .{ .stack_offset = stack_offset }; }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -4808,7 +5287,8 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { while (true) { i -= 1; if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| { - assert(mcv != .dead); + // TODO see comment in `airCondBr` and `airSwitch` + // assert(mcv != .dead); return mcv; } } @@ -4979,22 +5459,18 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { const error_type = typed_value.ty.errorUnionSet(); const payload_type = typed_value.ty.errorUnionPayload(); - if (typed_value.val.castTag(.eu_payload)) |pl| { + if (typed_value.val.castTag(.eu_payload)) |_| { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. return MCValue{ .immediate = 0 }; } - - _ = pl; - return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty}); } else { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); } } - - return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); + return self.lowerUnnamedConst(typed_value); }, .Struct => { return self.lowerUnnamedConst(typed_value); @@ -5041,6 +5517,25 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { return result; }, .Unspecified, .C => { + // Return values + if (ret_ty.zigTypeTag() == .NoReturn) { + result.return_value = .{ .unreach = {} }; + } else if (!ret_ty.hasRuntimeBits()) { + result.return_value = .{ .none = {} }; + } else { + const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); + if (ret_ty_size <= 8) { + const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size); + result.return_value = .{ .register = aliased_reg }; + } else { + // We simply make the return MCValue a stack offset. However, the actual value + // for the offset will be populated later. We will also push the stack offset + // value into .rdi register when we resolve the offset. + result.return_value = .{ .stack_offset = 0 }; + } + } + + // Input params // First, split into args that can be passed via registers. // This will make it easier to then push the rest of args in reverse // order on the stack. @@ -5084,7 +5579,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { } } - var next_stack_offset: u32 = 0; + var next_stack_offset: u32 = switch (result.return_value) { + .stack_offset => |off| @intCast(u32, off), + else => 0, + }; var count: usize = param_types.len; while (count > 0) : (count -= 1) { const i = count - 1; @@ -5108,28 +5606,15 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { } result.stack_align = 16; + // TODO fix this so that the 16byte alignment padding is at the current value of $rsp, and push + // the args onto the stack so that there is no padding between the first argument and + // the standard preamble. + // alignment padding | args ... | ret addr | $rbp | result.stack_byte_count = mem.alignForwardGeneric(u32, next_stack_offset, result.stack_align); }, - else => return self.fail("TODO implement function parameters for {} on x86_64", .{cc}), + else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), } - if (ret_ty.zigTypeTag() == .NoReturn) { - result.return_value = .{ .unreach = {} }; - } else if (!ret_ty.hasRuntimeBits()) { - result.return_value = .{ .none = {} }; - } else switch (cc) { - .Naked => unreachable, - .Unspecified, .C => { - const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); - if (ret_ty_size <= 8) { - const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size); - result.return_value = .{ .register = aliased_reg }; - } else { - return self.fail("TODO support more return types for x86_64 backend", .{}); - } - }, - else => return self.fail("TODO implement function return values for {}", .{cc}), - } return result; } diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 7e2a4272dc..2a66513670 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -162,6 +162,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void { => try emit.mirCondSetByte(tag, inst), .cond_mov_eq => try emit.mirCondMov(.cmove, inst), + .cond_mov_lt => try emit.mirCondMov(.cmovl, inst), + .cond_mov_below => try emit.mirCondMov(.cmovb, inst), .ret => try emit.mirRet(inst), @@ -1180,6 +1182,10 @@ const Tag = enum { cqo, cmove, cmovz, + cmovl, + cmovng, + cmovb, + cmovnae, fn isSetCC(tag: Tag) bool { return switch (tag) { @@ -1406,6 +1412,8 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { .lea => OpCode.oneByte(if (is_one_byte) 0x8c else 0x8d), .imul => OpCode.twoByte(0x0f, 0xaf), .cmove, .cmovz => OpCode.twoByte(0x0f, 0x44), + .cmovb, .cmovnae => OpCode.twoByte(0x0f, 0x42), + .cmovl, .cmovng => OpCode.twoByte(0x0f, 0x4c), else => null, }, .oi => return switch (tag) { diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 8055498439..9bb568a976 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -292,6 +292,8 @@ pub const Inst = struct { /// 0b10 reg1, dword ptr [reg2 + imm] /// 0b11 reg1, qword ptr [reg2 + imm] cond_mov_eq, + cond_mov_lt, + cond_mov_below, /// ops flags: form: /// 0b00 reg1 @@ -314,7 +316,8 @@ pub const Inst = struct { syscall, /// ops flags: form: - /// 0b00 reg1, imm32 + /// 0b00 reg1, imm32 if reg2 == .none + /// 0b00 reg1, reg2 /// TODO handle more cases @"test", diff --git a/src/codegen.zig b/src/codegen.zig index fd4321fee9..26a4478fb2 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -205,13 +205,62 @@ pub fn generateSymbol( .appended => {}, .externally_managed => |slice| { code.appendSliceAssumeCapacity(slice); - return Result{ .appended = {} }; }, .fail => |em| return Result{ .fail = em }, } } return Result{ .appended = {} }; }, + .repeated => { + const array = typed_value.val.castTag(.repeated).?.data; + const elem_ty = typed_value.ty.childType(); + const sentinel = typed_value.ty.sentinel(); + const len = typed_value.ty.arrayLen(); + + var index: u64 = 0; + while (index < len) : (index += 1) { + switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ + .ty = elem_ty, + .val = array, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |slice| { + code.appendSliceAssumeCapacity(slice); + }, + .fail => |em| return Result{ .fail = em }, + } + } + + if (sentinel) |sentinel_val| { + switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ + .ty = elem_ty, + .val = sentinel_val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |slice| { + code.appendSliceAssumeCapacity(slice); + }, + .fail => |em| return Result{ .fail = em }, + } + } + + return Result{ .appended = {} }; + }, + .empty_array_sentinel => { + const elem_ty = typed_value.ty.childType(); + const sentinel_val = typed_value.ty.sentinel().?; + switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ + .ty = elem_ty, + .val = sentinel_val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |slice| { + code.appendSliceAssumeCapacity(slice); + }, + .fail => |em| return Result{ .fail = em }, + } + return Result{ .appended = {} }; + }, else => return Result{ .fail = try ErrorMsg.create( bin_file.allocator, @@ -432,6 +481,75 @@ pub fn generateSymbol( return Result{ .appended = {} }; }, + .ErrorUnion => { + const error_ty = typed_value.ty.errorUnionSet(); + const payload_ty = typed_value.ty.errorUnionPayload(); + const is_payload = typed_value.val.errorUnionIsPayload(); + + const target = bin_file.options.target; + const abi_align = typed_value.ty.abiAlignment(target); + + { + const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero); + const begin = code.items.len; + switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ + .ty = error_ty, + .val = error_val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); + }, + .fail => |em| return Result{ .fail = em }, + } + const unpadded_end = code.items.len - begin; + const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); + const padding = try math.cast(usize, padded_end - unpadded_end); + + if (padding > 0) { + try code.writer().writeByteNTimes(0, padding); + } + } + + if (payload_ty.hasRuntimeBits()) { + const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef); + const begin = code.items.len; + switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ + .ty = payload_ty, + .val = payload_val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); + }, + .fail => |em| return Result{ .fail = em }, + } + const unpadded_end = code.items.len - begin; + const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); + const padding = try math.cast(usize, padded_end - unpadded_end); + + if (padding > 0) { + try code.writer().writeByteNTimes(0, padding); + } + } + + return Result{ .appended = {} }; + }, + .ErrorSet => { + const target = bin_file.options.target; + switch (typed_value.val.tag()) { + .@"error" => { + const name = typed_value.val.getError().?; + const kv = try bin_file.options.module.?.getErrorValue(name); + const endian = target.cpu.arch.endian(); + try code.writer().writeInt(u32, kv.value, endian); + }, + else => { + try code.writer().writeByteNTimes(0, @intCast(usize, typed_value.ty.abiSize(target))); + }, + } + return Result{ .appended = {} }; + }, else => |t| { return Result{ .fail = try ErrorMsg.create( diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 08903f7c05..4be478331a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3127,6 +3127,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl, em); + log.err("{s}", .{em.msg}); return error.AnalysisFail; }, }; diff --git a/test/behavior.zig b/test/behavior.zig index fb644ba59d..a034cf4b37 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -6,14 +6,19 @@ test { _ = @import("behavior/array.zig"); _ = @import("behavior/basic.zig"); _ = @import("behavior/bit_shifting.zig"); + _ = @import("behavior/bitcast.zig"); _ = @import("behavior/bitreverse.zig"); _ = @import("behavior/byteswap.zig"); + _ = @import("behavior/byval_arg_var.zig"); _ = @import("behavior/bool.zig"); _ = @import("behavior/bugs/394.zig"); + _ = @import("behavior/bugs/624.zig"); _ = @import("behavior/bugs/655.zig"); _ = @import("behavior/bugs/656.zig"); _ = @import("behavior/bugs/679.zig"); + _ = @import("behavior/bugs/704.zig"); _ = @import("behavior/bugs/1025.zig"); + _ = @import("behavior/bugs/1076.zig"); _ = @import("behavior/bugs/1111.zig"); _ = @import("behavior/bugs/1277.zig"); _ = @import("behavior/bugs/1310.zig"); @@ -26,150 +31,145 @@ test { _ = @import("behavior/bugs/2006.zig"); _ = @import("behavior/bugs/2346.zig"); _ = @import("behavior/bugs/2578.zig"); + _ = @import("behavior/bugs/2692.zig"); + _ = @import("behavior/bugs/2889.zig"); _ = @import("behavior/bugs/3007.zig"); + _ = @import("behavior/bugs/3046.zig"); _ = @import("behavior/bugs/3112.zig"); _ = @import("behavior/bugs/3367.zig"); + _ = @import("behavior/bugs/3586.zig"); + _ = @import("behavior/bugs/4560.zig"); + _ = @import("behavior/bugs/4769_a.zig"); + _ = @import("behavior/bugs/4769_b.zig"); + _ = @import("behavior/bugs/4954.zig"); _ = @import("behavior/bugs/6850.zig"); _ = @import("behavior/bugs/7250.zig"); + _ = @import("behavior/call.zig"); _ = @import("behavior/cast.zig"); _ = @import("behavior/comptime_memory.zig"); + _ = @import("behavior/defer.zig"); + _ = @import("behavior/enum.zig"); + _ = @import("behavior/error.zig"); + _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_delegation.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); + _ = @import("behavior/for.zig"); + _ = @import("behavior/generics.zig"); _ = @import("behavior/hasdecl.zig"); _ = @import("behavior/hasfield.zig"); + _ = @import("behavior/if.zig"); + _ = @import("behavior/import.zig"); + _ = @import("behavior/incomplete_struct_param_tld.zig"); + _ = @import("behavior/int_div.zig"); + _ = @import("behavior/inttoptr.zig"); _ = @import("behavior/ir_block_deps.zig"); + _ = @import("behavior/member_func.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); + _ = @import("behavior/null.zig"); _ = @import("behavior/optional.zig"); _ = @import("behavior/prefetch.zig"); + _ = @import("behavior/pointers.zig"); _ = @import("behavior/pub_enum.zig"); + _ = @import("behavior/ptrcast.zig"); _ = @import("behavior/reflection.zig"); + _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("behavior/slice.zig"); _ = @import("behavior/slice_sentinel_comptime.zig"); _ = @import("behavior/struct.zig"); + _ = @import("behavior/src.zig"); + _ = @import("behavior/this.zig"); _ = @import("behavior/truncate.zig"); + _ = @import("behavior/try.zig"); _ = @import("behavior/tuple.zig"); _ = @import("behavior/type.zig"); + _ = @import("behavior/type_info.zig"); + _ = @import("behavior/undefined.zig"); + _ = @import("behavior/underscore.zig"); + _ = @import("behavior/union.zig"); + _ = @import("behavior/usingnamespace.zig"); _ = @import("behavior/var_args.zig"); - _ = @import("behavior/int_div.zig"); + _ = @import("behavior/void.zig"); + _ = @import("behavior/while.zig"); // tests that don't pass for stage1 if (builtin.zig_backend != .stage1) { _ = @import("behavior/decltest.zig"); } - if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_aarch64) { - // Tests that pass (partly) for stage1, llvm backend, C backend, wasm backend. - _ = @import("behavior/bitcast.zig"); - _ = @import("behavior/bugs/624.zig"); - _ = @import("behavior/bugs/704.zig"); - _ = @import("behavior/bugs/1076.zig"); - _ = @import("behavior/bugs/2692.zig"); - _ = @import("behavior/bugs/2889.zig"); - _ = @import("behavior/bugs/3046.zig"); - _ = @import("behavior/bugs/3586.zig"); - _ = @import("behavior/bugs/4560.zig"); - _ = @import("behavior/bugs/4769_a.zig"); - _ = @import("behavior/bugs/4769_b.zig"); - _ = @import("behavior/bugs/4954.zig"); - _ = @import("behavior/byval_arg_var.zig"); - _ = @import("behavior/call.zig"); - _ = @import("behavior/defer.zig"); - _ = @import("behavior/enum.zig"); - _ = @import("behavior/error.zig"); - _ = @import("behavior/fn.zig"); - _ = @import("behavior/for.zig"); - _ = @import("behavior/generics.zig"); - _ = @import("behavior/if.zig"); - _ = @import("behavior/import.zig"); - _ = @import("behavior/incomplete_struct_param_tld.zig"); - _ = @import("behavior/inttoptr.zig"); - _ = @import("behavior/member_func.zig"); - _ = @import("behavior/null.zig"); - _ = @import("behavior/pointers.zig"); - _ = @import("behavior/ptrcast.zig"); - _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); - _ = @import("behavior/src.zig"); - _ = @import("behavior/this.zig"); - _ = @import("behavior/try.zig"); - _ = @import("behavior/type_info.zig"); - _ = @import("behavior/undefined.zig"); - _ = @import("behavior/underscore.zig"); - _ = @import("behavior/union.zig"); - _ = @import("behavior/usingnamespace.zig"); - _ = @import("behavior/void.zig"); - _ = @import("behavior/while.zig"); + if (builtin.zig_backend != .stage2_arm and + builtin.zig_backend != .stage2_x86_64 and + builtin.zig_backend != .stage2_aarch64 and + builtin.zig_backend != .stage2_wasm) + { + // Tests that pass for stage1, llvm backend, C backend + _ = @import("behavior/bugs/9584.zig"); + _ = @import("behavior/cast_int.zig"); + _ = @import("behavior/eval.zig"); + _ = @import("behavior/int128.zig"); + _ = @import("behavior/merge_error_sets.zig"); + _ = @import("behavior/translate_c_macros.zig"); - if (builtin.zig_backend != .stage2_wasm) { - // Tests that pass for stage1, llvm backend, C backend - _ = @import("behavior/bugs/9584.zig"); - _ = @import("behavior/cast_int.zig"); - _ = @import("behavior/eval.zig"); - _ = @import("behavior/int128.zig"); - _ = @import("behavior/merge_error_sets.zig"); - _ = @import("behavior/translate_c_macros.zig"); + if (builtin.zig_backend != .stage2_c) { + // Tests that pass for stage1 and the llvm backend. + _ = @import("behavior/atomics.zig"); + _ = @import("behavior/floatop.zig"); + _ = @import("behavior/math.zig"); + _ = @import("behavior/maximum_minimum.zig"); + _ = @import("behavior/popcount.zig"); + _ = @import("behavior/saturating_arithmetic.zig"); + _ = @import("behavior/sizeof_and_typeof.zig"); + _ = @import("behavior/switch.zig"); + _ = @import("behavior/widening.zig"); - if (builtin.zig_backend != .stage2_c) { - // Tests that pass for stage1 and the llvm backend. - _ = @import("behavior/atomics.zig"); - _ = @import("behavior/floatop.zig"); - _ = @import("behavior/math.zig"); - _ = @import("behavior/maximum_minimum.zig"); - _ = @import("behavior/popcount.zig"); - _ = @import("behavior/saturating_arithmetic.zig"); - _ = @import("behavior/sizeof_and_typeof.zig"); - _ = @import("behavior/switch.zig"); - _ = @import("behavior/widening.zig"); + if (builtin.zig_backend == .stage1) { + // Tests that only pass for the stage1 backend. + if (builtin.os.tag != .wasi) { + _ = @import("behavior/asm.zig"); + _ = @import("behavior/async_fn.zig"); + } + _ = @import("behavior/await_struct.zig"); + _ = @import("behavior/bugs/421.zig"); + _ = @import("behavior/bugs/529.zig"); + _ = @import("behavior/bugs/718.zig"); + _ = @import("behavior/bugs/726.zig"); + _ = @import("behavior/bugs/828.zig"); + _ = @import("behavior/bugs/920.zig"); + _ = @import("behavior/bugs/1120.zig"); + _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); - - if (builtin.zig_backend == .stage1) { - // Tests that only pass for the stage1 backend. - if (builtin.os.tag != .wasi) { - _ = @import("behavior/asm.zig"); - _ = @import("behavior/async_fn.zig"); - } - _ = @import("behavior/await_struct.zig"); - _ = @import("behavior/bugs/421.zig"); - _ = @import("behavior/bugs/529.zig"); - _ = @import("behavior/bugs/718.zig"); - _ = @import("behavior/bugs/726.zig"); - _ = @import("behavior/bugs/828.zig"); - _ = @import("behavior/bugs/920.zig"); - _ = @import("behavior/bugs/1120.zig"); - _ = @import("behavior/bugs/1421.zig"); - _ = @import("behavior/bugs/1607.zig"); - _ = @import("behavior/bugs/1851.zig"); - _ = @import("behavior/bugs/2114.zig"); - _ = @import("behavior/bugs/3384.zig"); - _ = @import("behavior/bugs/3742.zig"); - _ = @import("behavior/bugs/3779.zig"); - _ = @import("behavior/bugs/4328.zig"); - _ = @import("behavior/bugs/5398.zig"); - _ = @import("behavior/bugs/5413.zig"); - _ = @import("behavior/bugs/5474.zig"); - _ = @import("behavior/bugs/5487.zig"); - _ = @import("behavior/bugs/6456.zig"); - _ = @import("behavior/bugs/6781.zig"); - _ = @import("behavior/bugs/7003.zig"); - _ = @import("behavior/bugs/7027.zig"); - _ = @import("behavior/bugs/7047.zig"); - _ = @import("behavior/bugs/10147.zig"); - _ = @import("behavior/const_slice_child.zig"); - _ = @import("behavior/export_self_referential_type_info.zig"); - _ = @import("behavior/field_parent_ptr.zig"); - _ = @import("behavior/misc.zig"); - _ = @import("behavior/muladd.zig"); - _ = @import("behavior/select.zig"); - _ = @import("behavior/shuffle.zig"); - _ = @import("behavior/struct_contains_null_ptr_itself.zig"); - _ = @import("behavior/struct_contains_slice_of_itself.zig"); - _ = @import("behavior/switch_prong_err_enum.zig"); - _ = @import("behavior/switch_prong_implicit_cast.zig"); - _ = @import("behavior/typename.zig"); - _ = @import("behavior/union_with_members.zig"); - _ = @import("behavior/vector.zig"); - if (builtin.target.cpu.arch == .wasm32) { - _ = @import("behavior/wasm.zig"); - } + _ = @import("behavior/bugs/1607.zig"); + _ = @import("behavior/bugs/1851.zig"); + _ = @import("behavior/bugs/2114.zig"); + _ = @import("behavior/bugs/3384.zig"); + _ = @import("behavior/bugs/3742.zig"); + _ = @import("behavior/bugs/3779.zig"); + _ = @import("behavior/bugs/4328.zig"); + _ = @import("behavior/bugs/5398.zig"); + _ = @import("behavior/bugs/5413.zig"); + _ = @import("behavior/bugs/5474.zig"); + _ = @import("behavior/bugs/5487.zig"); + _ = @import("behavior/bugs/6456.zig"); + _ = @import("behavior/bugs/6781.zig"); + _ = @import("behavior/bugs/7003.zig"); + _ = @import("behavior/bugs/7027.zig"); + _ = @import("behavior/bugs/7047.zig"); + _ = @import("behavior/bugs/10147.zig"); + _ = @import("behavior/const_slice_child.zig"); + _ = @import("behavior/export_self_referential_type_info.zig"); + _ = @import("behavior/field_parent_ptr.zig"); + _ = @import("behavior/misc.zig"); + _ = @import("behavior/muladd.zig"); + _ = @import("behavior/select.zig"); + _ = @import("behavior/shuffle.zig"); + _ = @import("behavior/struct_contains_null_ptr_itself.zig"); + _ = @import("behavior/struct_contains_slice_of_itself.zig"); + _ = @import("behavior/switch_prong_err_enum.zig"); + _ = @import("behavior/switch_prong_implicit_cast.zig"); + _ = @import("behavior/typename.zig"); + _ = @import("behavior/union_with_members.zig"); + _ = @import("behavior/vector.zig"); + if (builtin.target.cpu.arch == .wasm32) { + _ = @import("behavior/wasm.zig"); } } } diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 6a899fcdc5..5518d40756 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -180,8 +180,6 @@ fn noop4() align(4) void {} test "function alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // function alignment is a compile error on wasm32/wasm64 @@ -199,7 +197,6 @@ test "implicitly decreasing fn alignment" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -226,8 +223,6 @@ test "@alignCast functions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // function alignment is a compile error on wasm32/wasm64 @@ -250,7 +245,6 @@ test "generic function with align param" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/array.zig b/test/behavior/array.zig index ba478fef93..0bbdad44c4 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -49,7 +49,7 @@ fn getArrayLen(a: []const u32) usize { test "array init with mult" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const a = 'a'; var i: [8]u8 = [2]u8{ a, 'b' } ** 4; @@ -112,7 +112,7 @@ test "array len field" { test "array with sentinels" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const S = struct { fn doTheTest(is_ct: bool) !void { @@ -179,7 +179,8 @@ 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_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; try testSingleItemPtrArrayIndexSlice(); comptime try testSingleItemPtrArrayIndexSlice(); @@ -205,7 +206,8 @@ fn doSomeMangling(array: *[4]u8) void { test "implicit cast zero sized array ptr to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; { var b = "".*; diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index d5081ca636..6c0fbd028a 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -117,7 +117,6 @@ fn first4KeysOfHomeRow() []const u8 { test "return string from function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); } @@ -231,7 +230,6 @@ test "compile time global reinterpret" { test "cast undefined" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const array: [100]u8 = undefined; const slice = @as([]const u8, &array); @@ -303,7 +301,6 @@ test "call function pointer in struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage1) return error.SkipZigTest; try expect(mem.eql(u8, f3(true), "a")); @@ -382,7 +379,6 @@ fn testMemcpyMemset() !void { test "variable is allowed to be a pointer to an opaque type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var x: i32 = 1234; @@ -425,7 +421,6 @@ test "array 2D const double ptr" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const rect_2d_vertexes = [_][1]f32{ @@ -476,7 +471,6 @@ fn testArray2DConstDoublePtr(ptr: *const f32) !void { test "double implicit cast in same expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; var x = @as(i32, @as(u16, nine())); try expect(x == 9); diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index 1bf33af57b..ac6bee8c73 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -7,6 +7,9 @@ const minInt = std.math.minInt; const native_endian = builtin.target.cpu.arch.endian(); test "@bitCast iX -> uX (32, 64)" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const bit_values = [_]usize{ 32, 64 }; inline for (bit_values) |bits| { @@ -17,6 +20,10 @@ test "@bitCast iX -> uX (32, 64)" { test "@bitCast iX -> uX (8, 16, 128)" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const bit_values = [_]usize{ 8, 16, 128 }; inline for (bit_values) |bits| { @@ -29,6 +36,8 @@ test "@bitCast iX -> uX exotic integers" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 }; @@ -66,6 +75,9 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe } test "nested bitcast" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const S = struct { fn moo(x: isize) !void { try expect(@intCast(isize, 42) == x); @@ -83,6 +95,9 @@ test "nested bitcast" { } test "@bitCast enum to its integer type" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const SOCK = enum(c_int) { A, B, @@ -100,11 +115,17 @@ test "@bitCast enum to its integer type" { // issue #3010: compiler segfault test "bitcast literal [4]u8 param to u32" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); try expect(ip == maxInt(u32)); } test "bitcast generates a temporary value" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + var y = @as(u16, 0x55AA); const x = @bitCast(u16, @bitCast([2]u8, y)); try expect(y == x); @@ -115,6 +136,8 @@ test "@bitCast packed structs at runtime and comptime" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const Full = packed struct { number: u16, @@ -151,6 +174,8 @@ test "@bitCast extern structs at runtime and comptime" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const Full = extern struct { number: u16, @@ -184,6 +209,8 @@ test "bitcast packed struct to integer and back" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const LevelUpMove = packed struct { move_id: u9, @@ -203,6 +230,9 @@ test "bitcast packed struct to integer and back" { } test "implicit cast to error union by returning" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const S = struct { fn entry() !void { try expect((func(-1) catch unreachable) == maxInt(u64)); @@ -220,6 +250,8 @@ test "bitcast packed struct literal to byte" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const Foo = packed struct { value: u8, @@ -233,6 +265,8 @@ test "comptime bitcast used in expression has the correct type" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const Foo = packed struct { value: u8, @@ -245,6 +279,8 @@ test "bitcast passed as tuple element" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const S = struct { fn foo(args: anytype) !void { @@ -257,6 +293,8 @@ test "bitcast passed as tuple element" { test "triple level result location with bitcast sandwich passed as tuple element" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const S = struct { fn foo(args: anytype) !void { diff --git a/test/behavior/bugs/1076.zig b/test/behavior/bugs/1076.zig index ab7d468a7b..6bf38eb617 100644 --- a/test/behavior/bugs/1076.zig +++ b/test/behavior/bugs/1076.zig @@ -1,8 +1,13 @@ const std = @import("std"); +const builtin = @import("builtin"); const mem = std.mem; const expect = std.testing.expect; test "comptime code should not modify constant data" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testCastPtrOfArrayToSliceAndPtr(); comptime try testCastPtrOfArrayToSliceAndPtr(); } diff --git a/test/behavior/bugs/1442.zig b/test/behavior/bugs/1442.zig index 5298d34acb..f0d524006c 100644 --- a/test/behavior/bugs/1442.zig +++ b/test/behavior/bugs/1442.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const Union = union(enum) { Text: []const u8, @@ -6,6 +7,8 @@ const Union = union(enum) { }; test "const error union field alignment" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; + var union_or_err: anyerror!Union = Union{ .Color = 1234 }; try std.testing.expect((union_or_err catch unreachable).Color == 1234); } diff --git a/test/behavior/bugs/2692.zig b/test/behavior/bugs/2692.zig index 1bc38a0274..0692c51b8c 100644 --- a/test/behavior/bugs/2692.zig +++ b/test/behavior/bugs/2692.zig @@ -1,8 +1,13 @@ +const builtin = @import("builtin"); + fn foo(a: []u8) void { _ = a; } test "address of 0 length array" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var pt: [0]u8 = undefined; foo(&pt); } diff --git a/test/behavior/bugs/2889.zig b/test/behavior/bugs/2889.zig index 473f6c615d..8bb70cb198 100644 --- a/test/behavior/bugs/2889.zig +++ b/test/behavior/bugs/2889.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const source = "A-"; @@ -26,6 +27,10 @@ fn parseNote() ?i32 { } test "fixed" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const result = parseNote(); try std.testing.expect(result.? == 9); } diff --git a/test/behavior/bugs/3046.zig b/test/behavior/bugs/3046.zig index 71e937f244..dc18256d33 100644 --- a/test/behavior/bugs/3046.zig +++ b/test/behavior/bugs/3046.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; const SomeStruct = struct { @@ -12,7 +13,10 @@ fn couldFail() anyerror!i32 { var some_struct: SomeStruct = undefined; test "fixed" { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) 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_c) return error.SkipZigTest; some_struct = SomeStruct{ .field = couldFail() catch @as(i32, 0), diff --git a/test/behavior/bugs/3586.zig b/test/behavior/bugs/3586.zig index 047cb5d205..f7266e9918 100644 --- a/test/behavior/bugs/3586.zig +++ b/test/behavior/bugs/3586.zig @@ -1,3 +1,5 @@ +const builtin = @import("builtin"); + const NoteParams = struct {}; const Container = struct { @@ -5,6 +7,9 @@ const Container = struct { }; test "fixed" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var ctr = Container{ .params = NoteParams{}, }; diff --git a/test/behavior/bugs/4560.zig b/test/behavior/bugs/4560.zig index 3119bd99b9..b3e40dd7f8 100644 --- a/test/behavior/bugs/4560.zig +++ b/test/behavior/bugs/4560.zig @@ -1,6 +1,10 @@ const std = @import("std"); +const builtin = @import("builtin"); test "fixed" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var s: S = .{ .a = 1, .b = .{ diff --git a/test/behavior/bugs/4954.zig b/test/behavior/bugs/4954.zig index 3dea934895..eaae4d8ba2 100644 --- a/test/behavior/bugs/4954.zig +++ b/test/behavior/bugs/4954.zig @@ -1,8 +1,14 @@ +const builtin = @import("builtin"); + fn f(buf: []u8) void { _ = &buf[@sizeOf(u32)]; } test "crash" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var buf: [4096]u8 = undefined; f(&buf); } diff --git a/test/behavior/bugs/624.zig b/test/behavior/bugs/624.zig index b8bf09f22e..b5288ebe17 100644 --- a/test/behavior/bugs/624.zig +++ b/test/behavior/bugs/624.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; const TestContext = struct { @@ -19,6 +20,9 @@ fn MemoryPool(comptime T: type) type { } test "foo" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var allocator = ContextAllocator{ .n = 10 }; try expect(allocator.n == 10); } diff --git a/test/behavior/bugs/704.zig b/test/behavior/bugs/704.zig index 15fe9419a6..352f61ac62 100644 --- a/test/behavior/bugs/704.zig +++ b/test/behavior/bugs/704.zig @@ -1,9 +1,14 @@ +const builtin = @import("builtin"); + const xxx = struct { pub fn bar(self: *xxx) void { _ = self; } }; test "bug 704" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x: xxx = undefined; x.bar(); } diff --git a/test/behavior/byval_arg_var.zig b/test/behavior/byval_arg_var.zig index a46a9ed0b2..3a1be9cc0c 100644 --- a/test/behavior/byval_arg_var.zig +++ b/test/behavior/byval_arg_var.zig @@ -1,8 +1,13 @@ const std = @import("std"); +const builtin = @import("builtin"); var result: []const u8 = "wrong"; test "pass string literal byvalue to a generic var param" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + start(); blowUpStack(10); diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index b574b25ce5..a9d363ddd1 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -5,6 +5,9 @@ const expectEqual = std.testing.expectEqual; const expectError = std.testing.expectError; test "break and continue inside loop inside defer expression" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + testBreakContInDefer(10); comptime testBreakContInDefer(10); } @@ -21,6 +24,9 @@ fn testBreakContInDefer(x: usize) void { } test "defer and labeled break" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var i = @as(usize, 0); blk: { @@ -32,6 +38,9 @@ test "defer and labeled break" { } test "errdefer does not apply to fn inside fn" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad); } @@ -47,6 +56,10 @@ fn testNestedFnErrDefer() anyerror!void { } test "return variable while defer expression in scope to modify it" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { try expect(notNull().? == 1); diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 9dd19d8f2e..d0f62842c1 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -11,6 +11,9 @@ fn shouldEqual(n: Number, expected: u3) !void { } test "enum to int" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try shouldEqual(Number.Zero, 0); try shouldEqual(Number.One, 1); try shouldEqual(Number.Two, 2); @@ -24,6 +27,9 @@ fn testIntToEnumEval(x: i32) !void { const IntToEnumNumber = enum { Zero, One, Two, Three, Four }; test "int to enum" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testIntToEnumEval(3); } @@ -553,6 +559,9 @@ const ValueCount257 = enum { }; test "enum sizes" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { try expect(@sizeOf(ValueCount1) == 0); try expect(@sizeOf(ValueCount2) == 1); @@ -562,6 +571,9 @@ test "enum sizes" { } test "enum literal equality" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const x = .hi; const y = .ok; const z = .hi; @@ -571,6 +583,9 @@ test "enum literal equality" { } test "enum literal cast to enum" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Color = enum { Auto, Off, On }; var color1: Color = .Auto; @@ -579,6 +594,9 @@ test "enum literal cast to enum" { } test "peer type resolution with enum literal" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Items = enum { one, two }; try expect(Items.two == .two); @@ -603,11 +621,19 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { } test "enum with specified tag values" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testEnumWithSpecifiedTagValues(MultipleChoice.C); comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C); } test "non-exhaustive enum" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const E = enum(u8) { a, b, _ }; @@ -649,6 +675,9 @@ test "non-exhaustive enum" { } test "empty non-exhaustive enum" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const E = enum(u8) { _ }; @@ -668,6 +697,10 @@ test "empty non-exhaustive enum" { } test "single field non-exhaustive enum" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const E = enum(u8) { a, _ }; fn doTheTest(y: u8) !void { @@ -708,6 +741,9 @@ const EnumWithTagValues = enum(u4) { D = 1 << 3, }; test "enum with tag values don't require parens" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(@enumToInt(EnumWithTagValues.C) == 0b0100); } @@ -724,11 +760,18 @@ const MultipleChoice2 = enum(u32) { }; test "cast integer literal to enum" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); } test "enum with specified and unspecified tag values" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); } @@ -752,6 +795,9 @@ const Small2 = enum(u2) { One, Two }; const Small = enum(u2) { One, Two, Three, Four }; test "set enum tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + { var x = Small.One; x = Small.Two; @@ -765,6 +811,9 @@ test "set enum tag type" { } test "casting enum to its tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testCastEnumTag(Small2.Two); comptime try testCastEnumTag(Small2.Two); } @@ -774,6 +823,9 @@ fn testCastEnumTag(value: Small2) !void { } test "enum with 1 field but explicit tag type should still have the tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Enum = enum(u8) { B = 2, }; @@ -781,6 +833,9 @@ test "enum with 1 field but explicit tag type should still have the tag type" { } test "signed integer as enum tag" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const SignedEnum = enum(i2) { A0 = -1, A1 = 0, @@ -793,6 +848,9 @@ test "signed integer as enum tag" { } test "enum with one member and custom tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const E = enum(u2) { One, }; @@ -804,6 +862,9 @@ test "enum with one member and custom tag type" { } test "enum with one member and u1 tag type @enumToInt" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Enum = enum(u1) { Test, }; @@ -811,6 +872,9 @@ test "enum with one member and u1 tag type @enumToInt" { } test "enum with comptime_int tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Enum = enum(comptime_int) { One = 3, Two = 2, @@ -820,6 +884,9 @@ test "enum with comptime_int tag type" { } test "enum with one member default to u0 tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const E0 = enum { X }; comptime try expect(Tag(E0) == u0); } @@ -836,11 +903,17 @@ fn doALoopThing(id: EnumWithOneMember) void { } test "comparison operator on enum with one member is comptime known" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + doALoopThing(EnumWithOneMember.Eof); } const State = enum { Start }; test "switch on enum with one member is comptime known" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var state = State.Start; switch (state) { State.Start => return, @@ -849,6 +922,9 @@ test "switch on enum with one member is comptime known" { } test "method call on an enum" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const E = enum { one, @@ -885,6 +961,10 @@ test "enum value allocation" { } test "enum literal casting to tagged union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Arch = union(enum) { x86_64, arm: Arm32, @@ -907,6 +987,10 @@ test "enum literal casting to tagged union" { const Bar = enum { A, B, C, D }; test "enum literal casting to error union with payload enum" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var bar: error{B}!Bar = undefined; bar = .B; // should never cast to the error set @@ -930,6 +1014,11 @@ test "exporting enum type and value" { } test "constant enum initialization with differing sizes" { + if (builtin.zig_backend == .stage2_x86_64) 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_wasm) return error.SkipZigTest; // TODO + try test3_1(test3_foo); try test3_2(test3_bar); } @@ -970,6 +1059,9 @@ fn test3_2(f: Test3Foo) !void { test "@tagName" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); @@ -984,6 +1076,9 @@ const BareNumber = enum { One, Two, Three }; test "@tagName non-exhaustive enum" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); @@ -993,6 +1088,9 @@ const NonExhaustive = enum(u8) { A, B, _ }; test "@tagName is null-terminated" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = struct { fn doTheTest(n: BareNumber) !void { @@ -1006,6 +1104,9 @@ test "@tagName is null-terminated" { test "tag name with assigned enum values" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const LocalFoo = enum(u8) { A = 1, @@ -1016,11 +1117,18 @@ test "tag name with assigned enum values" { } test "@tagName on enum literals" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); } test "enum literal casting to optional" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var bar: ?Bar = undefined; bar = .B; @@ -1045,6 +1153,9 @@ const bit_field_1 = BitFieldOfEnums{ test "bit field access with enum fields" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; var data = bit_field_1; try expect(getA(&data) == A.Two); @@ -1073,6 +1184,9 @@ fn getC(data: *const BitFieldOfEnums) C { } test "enum literal in array literal" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Items = enum { one, two }; const array = [_]Items{ .one, .two }; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 2e243d1d23..028bd26047 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -6,12 +6,18 @@ const expectEqual = std.testing.expectEqual; const mem = std.mem; test "error values" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const a = @errorToInt(error.err1); const b = @errorToInt(error.err2); try expect(a != b); } test "redefinition of error values allowed" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + shouldBeNotEqual(error.AnError, error.SecondError); } fn shouldBeNotEqual(a: anyerror, b: anyerror) void { @@ -19,6 +25,10 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void { } test "error binary operator" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const a = errBinaryOperatorG(true) catch 3; const b = errBinaryOperatorG(false) catch 3; try expect(a == 3); @@ -29,6 +39,9 @@ fn errBinaryOperatorG(x: bool) anyerror!isize { } test "empty error union" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const x = error{} || error{}; _ = x; } @@ -48,10 +61,18 @@ pub fn baz() anyerror!i32 { } test "error wrapping" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect((baz() catch unreachable) == 15); } test "unwrap simple value from error" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const i = unwrapSimpleValueFromErrorDo() catch unreachable; try expect(i == 13); } @@ -60,6 +81,10 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize { } test "error return in assignment" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + doErrReturnInAssignment() catch unreachable; } @@ -73,12 +98,19 @@ fn makeANonErr() anyerror!i32 { } test "syntax: optional operator in front of error union operator" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { try expect(?(anyerror!i32) == ?(anyerror!i32)); } } test "widen cast integer payload of error union function call" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn errorable() !u64 { var x = @as(u64, try number()); @@ -93,12 +125,19 @@ test "widen cast integer payload of error union function call" { } test "debug info for optional error set" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const SomeError = error{Hello}; var a_local_variable: ?SomeError = null; _ = a_local_variable; } test "implicit cast to optional to error union to return result loc" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn entry() !void { var x: Foo = undefined; @@ -118,6 +157,9 @@ test "implicit cast to optional to error union to return result loc" { } test "error: fn returning empty error set can be passed as fn returning any error" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + entry(); comptime entry(); } @@ -482,6 +524,9 @@ test "error union comptime caching" { test "@errorName" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try expect(mem.eql(u8, @errorName(error.AnError), "AnError")); try expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); @@ -494,6 +539,9 @@ fn gimmeItBroke() anyerror { test "@errorName sentinel length matches slice length" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const name = testBuiltinErrorName(error.FooBar); const length: usize = 6; diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 17a3d9a93b..c4779379c5 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -5,6 +5,9 @@ const expect = testing.expect; const expectEqual = testing.expectEqual; test "params" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(testParamsAdd(22, 11) == 33); } fn testParamsAdd(a: i32, b: i32) i32 { @@ -12,6 +15,9 @@ fn testParamsAdd(a: i32, b: i32) i32 { } test "local variables" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + testLocVars(2); } fn testLocVars(b: i32) void { @@ -20,6 +26,9 @@ fn testLocVars(b: i32) void { } test "mutable local variables" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var zero: i32 = 0; try expect(zero == 0); @@ -31,6 +40,9 @@ test "mutable local variables" { } test "separate block scopes" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + { const no_conflict: i32 = 5; try expect(no_conflict == 5); @@ -47,10 +59,16 @@ fn @"weird function name"() i32 { return 1234; } test "weird function name" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(@"weird function name"() == 1234); } test "assign inline fn to const variable" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const a = inlineFn; a(); } @@ -68,6 +86,9 @@ fn outer(y: u32) *const fn (u32) u32 { } test "return inner function which references comptime variable of outer function" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage1) return error.SkipZigTest; var func = outer(10); @@ -76,6 +97,9 @@ test "return inner function which references comptime variable of outer function test "discard the result of a function that returns a struct" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn entry() void { _ = func(); @@ -97,6 +121,9 @@ test "discard the result of a function that returns a struct" { test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = struct { field: u32, @@ -129,6 +156,9 @@ test "inline function call that calls optional function pointer, return pointer } test "implicit cast function unreachable return" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + wantsFnWithVoid(fnWithUnreachable); } @@ -143,6 +173,8 @@ fn fnWithUnreachable() noreturn { test "extern struct with stdcallcc fn pointer" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = extern struct { ptr: *const fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32, @@ -170,10 +202,16 @@ fn fComplexCallconvRet(x: u32) callconv(blk: { } 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; + try expect(fComplexCallconvRet(3).x == 9); } test "pass by non-copying value" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); } @@ -187,6 +225,10 @@ fn addPointCoords(pt: Point) i32 { } test "pass by non-copying value through var arg" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3); } @@ -196,6 +238,9 @@ fn addPointCoordsVar(pt: anytype) !i32 { } test "pass by non-copying value as method" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var pt = Point2{ .x = 1, .y = 2 }; try expect(pt.addPointCoords() == 3); } @@ -210,6 +255,9 @@ const Point2 = struct { }; test "pass by non-copying value as method, which is generic" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var pt = Point3{ .x = 1, .y = 2 }; try expect(pt.addPointCoords(i32) == 3); } @@ -225,6 +273,9 @@ const Point3 = struct { }; test "pass by non-copying value as method, at comptime" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { var pt = Point2{ .x = 1, .y = 2 }; try expect(pt.addPointCoords() == 3); @@ -232,6 +283,9 @@ test "pass by non-copying value as method, at comptime" { } 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; + const S = struct { fn entry() !void { var x = Foo{ @@ -255,6 +309,10 @@ test "implicit cast fn call result to optional in field result" { } test "void parameters" { + if (builtin.zig_backend == .stage2_x86_64) 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_c) return error.SkipZigTest; // TODO try voidFun(1, void{}, 2, {}); } @@ -267,6 +325,9 @@ fn voidFun(a: i32, b: void, c: i32, d: void) !void { } test "call function with empty string" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + acceptsString(""); } @@ -301,6 +362,9 @@ fn fn4() u32 { } test "number literal as an argument" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try numberLiteralArg(3); comptime try numberLiteralArg(3); } @@ -311,6 +375,10 @@ fn numberLiteralArg(a: anytype) !void { test "function call with anon list literal" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { try consumeVec(.{ 9, 8, 7 }); @@ -327,6 +395,9 @@ test "function call with anon list literal" { } test "ability to give comptime types and non comptime types to same parameter" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var x: i32 = 1; diff --git a/test/behavior/for.zig b/test/behavior/for.zig index 2ec5a74d73..011363bffd 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -5,6 +5,9 @@ const expectEqual = std.testing.expectEqual; const mem = std.mem; test "continue in for loop" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const array = [_]i32{ 1, 2, 3, 4, 5 }; var sum: i32 = 0; for (array) |x| { @@ -18,6 +21,9 @@ test "continue in for loop" { } test "break from outer for loop" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testBreakOuter(); comptime try testBreakOuter(); } @@ -35,6 +41,9 @@ fn testBreakOuter() !void { } test "continue outer for loop" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testContinueOuter(); comptime try testContinueOuter(); } @@ -52,6 +61,9 @@ fn testContinueOuter() !void { } test "ignore lval with underscore (for loop)" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + for ([_]void{}) |_, i| { _ = i; for ([_]void{}) |_, j| { @@ -63,7 +75,10 @@ test "ignore lval with underscore (for loop)" { } test "basic for loop" { - if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; @@ -104,6 +119,10 @@ test "basic for loop" { } test "for with null and T peer types and inferred result location type" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest(slice: []const u8) !void { if (for (slice) |item| { @@ -121,6 +140,9 @@ 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_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn entry(t: bool, f: bool) !void { var buf: [10]u8 = undefined; diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 1942e82340..e76cca4e1f 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -5,6 +5,9 @@ const expect = testing.expect; const expectEqual = testing.expectEqual; test "one param, explicit comptime" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x: usize = 0; x += checkSize(i32); x += checkSize(bool); @@ -17,6 +20,9 @@ fn checkSize(comptime T: type) usize { } test "simple generic fn" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(max(i32, 3, -1) == 3); try expect(max(u8, 1, 100) == 100); if (builtin.zig_backend == .stage1) { @@ -37,6 +43,9 @@ fn add(comptime a: i32, b: i32) i32 { const the_max = max(u32, 1234, 5678); test "compile time generic eval" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(the_max == 5678); } @@ -53,12 +62,20 @@ fn sameButWithFloats(a: f64, b: f64) f64 { } test "fn with comptime args" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(gimmeTheBigOne(1234, 5678) == 5678); try expect(shouldCallSameInstance(34, 12) == 34); try expect(sameButWithFloats(0.43, 0.49) == 0.49); } test "anytype params" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(max_i32(12, 34) == 34); try expect(max_f64(1.2, 3.4) == 3.4); comptime { @@ -80,6 +97,10 @@ fn max_f64(a: f64, b: f64) f64 { } test "type constructed by comptime function call" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var l: SimpleList(10) = undefined; l.array[0] = 10; l.array[1] = 11; @@ -99,6 +120,9 @@ fn SimpleList(comptime L: usize) type { } test "function with return type type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var list: List(i32) = undefined; var list2: List(i32) = undefined; list.length = 10; @@ -120,6 +144,9 @@ pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { } test "const decls in struct" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(GenericDataThing(3).count_plus_one == 4); } fn GenericDataThing(comptime count: isize) type { @@ -129,6 +156,9 @@ fn GenericDataThing(comptime count: isize) type { } test "use generic param in generic param" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(aGenericFn(i32, 3, 4) == 7); } fn aGenericFn(comptime T: type, comptime a: T, b: T) T { @@ -136,6 +166,9 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T { } test "generic fn with implicit cast" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(getFirstByte(u8, &[_]u8{13}) == 13); try expect(getFirstByte(u16, &[_]u16{ 0, @@ -150,6 +183,9 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 { } 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; + const A = 128; const S = struct { @@ -165,8 +201,10 @@ test "generic fn keeps non-generic parameter types" { } test "array of generic fns" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + try expect(foos[0](true)); try expect(!foos[1](true)); } @@ -185,7 +223,8 @@ fn foo2(arg: anytype) bool { test "generic struct" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; var a1 = GenNode(i32){ .value = 13, .next = null, diff --git a/test/behavior/if.zig b/test/behavior/if.zig index 7f80229332..068f3bdd21 100644 --- a/test/behavior/if.zig +++ b/test/behavior/if.zig @@ -4,6 +4,9 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; test "if statements" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + shouldBeEqual(1, 1); firstEqlThird(2, 1, 2); } @@ -27,6 +30,9 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void { } test "else if expression" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(elseIfExpressionF(1) == 1); } fn elseIfExpressionF(c: u8) u8 { @@ -44,6 +50,10 @@ var global_with_val: anyerror!u32 = 0; var global_with_err: anyerror!u32 = error.SomeError; test "unwrap mutable global var" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (global_with_val) |v| { try expect(v == 0); } else |_| { @@ -57,6 +67,9 @@ test "unwrap mutable global var" { } test "labeled break inside comptime if inside runtime if" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var answer: i32 = 0; var c = true; if (c) { @@ -68,6 +81,9 @@ test "labeled break inside comptime if inside runtime if" { } test "const result loc, runtime if cond, else unreachable" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Num = enum { One, Two }; var t = true; @@ -76,6 +92,10 @@ test "const result loc, runtime if cond, else unreachable" { } test "if copies its payload" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var tmp: ?i32 = 10; diff --git a/test/behavior/incomplete_struct_param_tld.zig b/test/behavior/incomplete_struct_param_tld.zig index a1e0672c7b..3f69c1cbbd 100644 --- a/test/behavior/incomplete_struct_param_tld.zig +++ b/test/behavior/incomplete_struct_param_tld.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const expect = @import("std").testing.expect; const A = struct { @@ -21,6 +22,8 @@ fn foo(a: A) i32 { } test "incomplete struct param top level declaration" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const a = A{ .b = B{ .c = C{ .x = 13 }, diff --git a/test/behavior/inttoptr.zig b/test/behavior/inttoptr.zig index 5c1acf51cd..8a642d7803 100644 --- a/test/behavior/inttoptr.zig +++ b/test/behavior/inttoptr.zig @@ -3,6 +3,8 @@ const builtin = @import("builtin"); test "casting integer address to function pointer" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; addressToFunction(); comptime addressToFunction(); @@ -14,6 +16,10 @@ fn addressToFunction() void { } test "mutate through ptr initialized with constant intToPtr value" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + forceCompilerAnalyzeBranchHardCodedPtrDereference(false); } diff --git a/test/behavior/member_func.zig b/test/behavior/member_func.zig index 3e4895e729..61280a6b11 100644 --- a/test/behavior/member_func.zig +++ b/test/behavior/member_func.zig @@ -28,6 +28,9 @@ const HasFuncs = struct { test "standard field calls" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try expect(HasFuncs.one(0) == 1); try expect(HasFuncs.two(0) == 2); @@ -69,6 +72,9 @@ test "standard field calls" { test "@field field calls" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try expect(@field(HasFuncs, "one")(0) == 1); try expect(@field(HasFuncs, "two")(0) == 2); diff --git a/test/behavior/null.zig b/test/behavior/null.zig index 35ecafff80..43c9355f3c 100644 --- a/test/behavior/null.zig +++ b/test/behavior/null.zig @@ -29,6 +29,10 @@ test "optional type" { } test "test maybe object and get a pointer to the inner value" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var maybe_bool: ?bool = true; if (maybe_bool) |*b| { @@ -45,6 +49,10 @@ test "rhs maybe unwrap return" { } test "maybe return" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try maybeReturnImpl(); comptime try maybeReturnImpl(); } @@ -61,6 +69,10 @@ fn foo(x: ?i32) ?bool { } test "test null runtime" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testTestNullRuntime(null); } fn testTestNullRuntime(x: ?i32) !void { @@ -69,6 +81,9 @@ fn testTestNullRuntime(x: ?i32) !void { } test "optional void" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try optionalVoidImpl(); comptime try optionalVoidImpl(); } @@ -89,6 +104,9 @@ fn bar(x: ?void) ?void { const Empty = struct {}; test "optional struct{}" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + _ = try optionalEmptyStructImpl(); _ = comptime try optionalEmptyStructImpl(); } @@ -107,17 +125,25 @@ fn baz(x: ?Empty) ?Empty { } test "null with default unwrap" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const x: i32 = null orelse 1; try expect(x == 1); } test "optional pointer to 0 bit type null value at runtime" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const EmptyStruct = struct {}; var x: ?*EmptyStruct = null; try expect(x == null); } test "if var maybe pointer" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(shouldBeAPlus1(Particle{ .a = 14, .b = 1, @@ -159,6 +185,9 @@ const here_is_a_null_literal = SillyStruct{ .context = null }; test "unwrap optional which is field of global var" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; struct_with_optional.field = null; if (struct_with_optional.field) |payload| { diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index a642da858b..2832dd01d3 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -17,6 +17,10 @@ fn testDerefPtr() !void { } test "pointer arithmetic" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var ptr: [*]const u8 = "abcd"; try expect(ptr[0] == 'a'); @@ -61,6 +65,10 @@ test "initialize const optional C pointer to null" { } test "assigning integer to C pointer" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x: i32 = 0; var y: i32 = 1; var ptr: [*c]u8 = 0; @@ -75,6 +83,10 @@ test "assigning integer to C pointer" { } test "C pointer comparison and arithmetic" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var ptr1: [*c]u32 = 0; @@ -133,6 +145,10 @@ test "peer type resolution with C pointers" { } test "implicit casting between C pointer and optional non-C pointer" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var slice: []const u8 = "aoeu"; const opt_many_ptr: ?[*]const u8 = slice.ptr; var ptr_opt_many_ptr = &opt_many_ptr; @@ -172,6 +188,9 @@ test "compare equality of optional and non-optional pointer" { test "allowzero pointer and slice" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; var ptr = @intToPtr([*]allowzero i32, 0); var opt_ptr: ?[*]allowzero i32 = ptr; 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 df116c0565..8ef037cd2c 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 @@ -1,9 +1,14 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; const mem = std.mem; var ok: bool = false; test "reference a variable in an if after an if in the 2nd switch prong" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try foo(true, Num.Two, false, "aoeu"); try expect(!ok); try foo(false, Num.One, false, "aoeu"); diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 5123350e20..d6ab46e757 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -248,7 +248,6 @@ test "result location zero sized array inside struct field implicit cast to slic 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_x86_64) return error.SkipZigTest; var an_array = [_]u8{ 1, 2, 3 }; try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); diff --git a/test/behavior/src.zig b/test/behavior/src.zig index 9dd1badaae..bb0a0971b4 100644 --- a/test/behavior/src.zig +++ b/test/behavior/src.zig @@ -1,8 +1,12 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; test "@src" { - try doTheTest(); + // TODO why is this failing on stage1? + return error.SkipZigTest; + + // try doTheTest(); } fn doTheTest() !void { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index bd04868f68..99dec11bf9 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -86,7 +86,8 @@ const StructFoo = struct { test "structs" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; var foo: StructFoo = undefined; @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); @@ -248,7 +249,8 @@ 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_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -310,7 +312,6 @@ test "struct point to self" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO var root: Node = undefined; root.val.x = 1; @@ -350,7 +351,6 @@ test "return empty struct from fn" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO _ = testReturnEmptyStructFromFn(); } @@ -364,7 +364,6 @@ test "pass slice of empty struct to fn" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1); } @@ -409,7 +408,6 @@ test "align 1 field before self referential align 8 field as slice return type" if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const result = alloc(Expr); try expect(result.len == 0); @@ -670,7 +668,6 @@ test "default struct initialization fields" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { a: i32 = 1234, @@ -936,7 +933,6 @@ test "anonymous struct literal syntax" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { const Point = struct { diff --git a/test/behavior/this.zig b/test/behavior/this.zig index 0fcfd5910c..49b7ca69d9 100644 --- a/test/behavior/this.zig +++ b/test/behavior/this.zig @@ -1,4 +1,5 @@ const expect = @import("std").testing.expect; +const builtin = @import("builtin"); const module = @This(); @@ -20,10 +21,16 @@ fn add(x: i32, y: i32) i32 { } test "this refer to module call private fn" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(module.add(1, 2) == 3); } test "this refer to container" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var pt: Point(i32) = undefined; pt.x = 12; pt.y = 34; diff --git a/test/behavior/try.zig b/test/behavior/try.zig index 029d946588..cd8b03afab 100644 --- a/test/behavior/try.zig +++ b/test/behavior/try.zig @@ -1,6 +1,12 @@ -const expect = @import("std").testing.expect; +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; test "try on error union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try tryOnErrorUnionImpl(); comptime try tryOnErrorUnionImpl(); } @@ -19,6 +25,9 @@ fn returnsTen() anyerror!i32 { } test "try without vars" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const result1 = if (failIfTrue(true)) 1 else |_| @as(i32, 2); try expect(result1 == 2); @@ -35,6 +44,9 @@ fn failIfTrue(ok: bool) anyerror!void { } test "try then not executed with assignment" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (failIfTrue(true)) { unreachable; } else |err| { diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index 8b71380de2..a3582719fd 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -186,6 +186,10 @@ fn testErrorSet() !void { } test "type info: enum info" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testEnum(); comptime try testEnum(); } @@ -249,6 +253,9 @@ fn testUnion() !void { } test "type info: struct info" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testStruct(); comptime try testStruct(); } @@ -439,6 +446,10 @@ test "type info for async frames" { } test "Declarations are returned in declaration order" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const a = 1; const b = 2; diff --git a/test/behavior/undefined.zig b/test/behavior/undefined.zig index 280fbaf550..dcea219593 100644 --- a/test/behavior/undefined.zig +++ b/test/behavior/undefined.zig @@ -16,6 +16,8 @@ test "init static array to undefined" { // This test causes `initStaticArray()` to be codegen'd, and the // C backend does not yet support returning arrays, so it fails if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try expect(static_array[0] == 1); try expect(static_array[4] == 2); @@ -43,6 +45,9 @@ fn setFooX(foo: *Foo) void { } test "assign undefined to struct" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { var foo: Foo = undefined; setFooX(&foo); @@ -56,6 +61,9 @@ test "assign undefined to struct" { } test "assign undefined to struct with method" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { var foo: Foo = undefined; foo.setFooXMethod(); @@ -69,6 +77,9 @@ test "assign undefined to struct with method" { } test "type name of undefined" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const x = undefined; try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)")); } diff --git a/test/behavior/underscore.zig b/test/behavior/underscore.zig index b701aac044..c15f8105aa 100644 --- a/test/behavior/underscore.zig +++ b/test/behavior/underscore.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; test "ignore lval with underscore" { @@ -6,6 +7,10 @@ test "ignore lval with underscore" { } test "ignore lval with underscore (while loop)" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + while (optionalReturnError()) |_| { while (optionalReturnError()) |_| { break; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 2e29d26941..5a7fbbd98e 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -10,6 +10,10 @@ const Foo = union { }; test "basic unions" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var foo = Foo{ .int = 1 }; try expect(foo.int == 1); foo = Foo{ .float = 12.34 }; @@ -17,6 +21,10 @@ test "basic unions" { } test "init union with runtime value" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var foo: Foo = undefined; setFloat(&foo, 12.34); @@ -35,6 +43,9 @@ fn setInt(foo: *Foo, x: i32) void { } test "comptime union field access" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { var foo = Foo{ .int = 0 }; try expect(foo.int == 0); @@ -50,6 +61,10 @@ const FooExtern = extern union { }; test "basic extern unions" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var foo = FooExtern{ .int = 1 }; try expect(foo.int == 1); foo.float = 12.34; @@ -61,10 +76,16 @@ const ExternPtrOrInt = extern union { int: u64, }; test "extern union size" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime try expect(@sizeOf(ExternPtrOrInt) == 8); } test "0-sized extern union definition" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const U = extern union { a: void, const f = 1; @@ -94,6 +115,10 @@ const err = @as(anyerror!Agg, Agg{ const array = [_]Value{ v1, v2, v1, v2 }; test "unions embedded in aggregate types" { + if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + switch (array[1]) { Value.Array => |arr| try expect(arr[4] == 3), else => unreachable, @@ -105,6 +130,9 @@ test "unions embedded in aggregate types" { } test "access a member of tagged union with conflicting enum tag name" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Bar = union(enum) { A: A, B: B, @@ -117,6 +145,10 @@ test "access a member of tagged union with conflicting enum tag name" { } test "constant tagged union with payload" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var empty = TaggedUnionWithPayload{ .Empty = {} }; var full = TaggedUnionWithPayload{ .Full = 13 }; shouldBeEmpty(empty); @@ -143,6 +175,9 @@ const TaggedUnionWithPayload = union(enum) { }; test "union alignment" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime { try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf([9]u8)); try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf(u64)); @@ -162,11 +197,18 @@ const Payload = union(Letter) { }; test "union with specified enum tag" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try doTest(); comptime try doTest(); } test "packed union generates correctly aligned LLVM type" { + if (builtin.zig_backend == .stage2_x86_64) 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 == .stage1) return error.SkipZigTest; const U = packed union { @@ -204,6 +246,10 @@ fn testComparison() !void { } test "comparison between union and enum literal" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testComparison(); comptime try testComparison(); } @@ -215,6 +261,10 @@ const TheUnion = union(TheTag) { C: i32, }; test "cast union to tag type of union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testCastUnionToTag(); comptime try testCastUnionToTag(); } @@ -225,12 +275,19 @@ fn testCastUnionToTag() !void { } test "union field access gives the enum values" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(TheUnion.A == TheTag.A); try expect(TheUnion.B == TheTag.B); try expect(TheUnion.C == TheTag.C); } test "cast tag type of union to union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x: Value2 = Letter2.B; try expect(@as(Letter2, x) == Letter2.B); } @@ -242,6 +299,10 @@ const Value2 = union(Letter2) { }; test "implicit cast union to its tag type" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x: Value2 = Letter2.B; try expect(x == Letter2.B); try giveMeLetterB(x); @@ -258,6 +319,10 @@ pub const PackThis = union(enum) { }; test "constant packed union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); } @@ -272,6 +337,10 @@ const MultipleChoice = union(enum(u32)) { D = 1000, }; test "simple union(enum(u32))" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x = MultipleChoice.C; try expect(x == MultipleChoice.C); try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60); @@ -282,6 +351,9 @@ const PackedPtrOrInt = packed union { int: u64, }; test "packed union size" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime try expect(@sizeOf(PackedPtrOrInt) == 8); } @@ -289,10 +361,17 @@ const ZeroBits = union { OnlyField: void, }; test "union with only 1 field which is void should be zero bits" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime try expect(@sizeOf(ZeroBits) == 0); } test "tagged union initialization with runtime void" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(testTaggedUnionInit({})); } @@ -309,6 +388,10 @@ fn testTaggedUnionInit(x: anytype) bool { pub const UnionEnumNoPayloads = union(enum) { A, B }; test "tagged union with no payloads" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const a = UnionEnumNoPayloads{ .B = {} }; switch (a) { Tag(UnionEnumNoPayloads).A => @panic("wrong"), @@ -317,6 +400,10 @@ test "tagged union with no payloads" { } test "union with only 1 field casted to its enum type" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Literal = union(enum) { Number: f64, Bool: bool, @@ -334,6 +421,9 @@ test "union with only 1 field casted to its enum type" { } test "union with one member defaults to u0 tag type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const U0 = union(enum) { X: u32, }; @@ -348,6 +438,10 @@ const Foo1 = union(enum) { var glbl: Foo1 = undefined; test "global union with single field is correctly initialized" { + if (builtin.zig_backend == .stage2_x86_64) 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_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO @@ -365,6 +459,10 @@ pub const FooUnion = union(enum) { var glbl_array: [2]FooUnion = undefined; test "initialize global array of union" { + if (builtin.zig_backend == .stage2_x86_64) 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_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; @@ -375,6 +473,10 @@ test "initialize global array of union" { } test "update the tag value for zero-sized unions" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = union(enum) { U0: void, U1: void, @@ -386,6 +488,10 @@ test "update the tag value for zero-sized unions" { } test "union initializer generates padding only if needed" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const U = union(enum) { A: u24, }; @@ -395,6 +501,10 @@ test "union initializer generates padding only if needed" { } test "runtime tag name with single field" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const U = union(enum) { A: i32, }; @@ -404,6 +514,10 @@ test "runtime tag name with single field" { } test "method call on an empty union" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const MyUnion = union(MyUnionTag) { pub const MyUnionTag = enum { X1, X2 }; @@ -441,6 +555,10 @@ const FooNoVoid = union(enum) { const Baz = enum { A, B, C, D }; test "tagged union type" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const foo1 = TaggedFoo{ .One = 13 }; const foo2 = TaggedFoo{ .Two = Point{ @@ -460,6 +578,10 @@ test "tagged union type" { } test "tagged union as return value" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + switch (returnAnInt(13)) { TaggedFoo.One => |value| try expect(value == 13), else => unreachable, @@ -471,6 +593,10 @@ fn returnAnInt(x: i32) TaggedFoo { } test "tagged union with all void fields but a meaningful tag" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { const B = union(enum) { c: C, @@ -496,6 +622,9 @@ test "tagged union with all void fields but a meaningful tag" { test "union(enum(u32)) with specified and unspecified tag values" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; comptime try expect(Tag(Tag(MultipleChoice2)) == u32); try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); @@ -558,6 +687,10 @@ const PartialInstWithPayload = union(enum) { }; test "union with only 1 field casted to its enum type which has enum value specified" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const Literal = union(enum) { Number: f64, Bool: bool, @@ -638,6 +771,10 @@ fn Setter(attr: Attribute) type { } test "return union init with void payload" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn entry() !void { try expect(func().state == State.one); @@ -948,6 +1085,9 @@ test "union enum type gets a separate scope" { test "global variable struct contains union initialized to non-most-aligned field" { 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const T = struct { const U = union(enum) { diff --git a/test/behavior/usingnamespace.zig b/test/behavior/usingnamespace.zig index ad47762c16..611b9888fa 100644 --- a/test/behavior/usingnamespace.zig +++ b/test/behavior/usingnamespace.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; const A = struct { @@ -10,6 +11,9 @@ const C = struct { }; test "basic usingnamespace" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try std.testing.expect(C.B == bool); } @@ -20,6 +24,9 @@ fn Foo(comptime T: type) type { } test "usingnamespace inside a generic struct" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const std2 = Foo(std); const testing2 = Foo(std.testing); try std2.testing.expect(true); @@ -31,11 +38,17 @@ usingnamespace struct { }; test "usingnamespace does not redeclare an imported variable" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + comptime try std.testing.expect(@This().foo == 42); } usingnamespace @import("usingnamespace/foo.zig"); test "usingnamespace omits mixing in private functions" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(@This().privateFunction()); try expect(!@This().printText()); } @@ -44,10 +57,16 @@ fn privateFunction() bool { } test { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + _ = @import("usingnamespace/import_segregation.zig"); } usingnamespace @import("usingnamespace/a.zig"); test "two files usingnamespace import each other" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(@This().ok()); } diff --git a/test/behavior/void.zig b/test/behavior/void.zig index 17778d42de..800dbb1b00 100644 --- a/test/behavior/void.zig +++ b/test/behavior/void.zig @@ -1,4 +1,5 @@ const expect = @import("std").testing.expect; +const builtin = @import("builtin"); const Foo = struct { a: void, @@ -18,6 +19,9 @@ test "compare void with void compile time known" { } test "iterate over a void slice" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var j: usize = 0; for (times(10)) |_, i| { try expect(i == j); @@ -30,11 +34,18 @@ fn times(n: usize) []const void { } test "void optional" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x: ?void = {}; try expect(x != null); } test "void array as a local variable initializer" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var x = [_]void{{}} ** 1004; _ = x[0]; } diff --git a/test/behavior/while.zig b/test/behavior/while.zig index 15dd9ee54c..86724d166a 100644 --- a/test/behavior/while.zig +++ b/test/behavior/while.zig @@ -1,7 +1,11 @@ const std = @import("std"); +const builtin = @import("builtin"); const expect = std.testing.expect; test "while loop" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + var i: i32 = 0; while (i < 4) { i += 1; @@ -19,6 +23,9 @@ fn whileLoop2() i32 { } test "static eval while" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + try expect(static_eval_while_number == 1); } const static_eval_while_number = staticWhileLoop1(); @@ -98,6 +105,10 @@ fn testBreakOuter() void { } test "while copies its payload" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var tmp: ?i32 = 10; @@ -113,6 +124,8 @@ test "while copies its payload" { } test "continue and break" { + if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; + try runContinueAndBreakTest(); try expect(continue_and_break_counter == 8); } @@ -131,6 +144,10 @@ fn runContinueAndBreakTest() !void { } test "while with optional as condition" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + numbers_left = 10; var sum: i32 = 0; while (getNumberOrNull()) |value| { @@ -140,6 +157,10 @@ test "while with optional as condition" { } test "while with optional as condition with else" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + numbers_left = 10; var sum: i32 = 0; var got_else: i32 = 0; @@ -154,6 +175,10 @@ test "while with optional as condition with else" { } test "while with error union condition" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + numbers_left = 10; var sum: i32 = 0; var got_else: i32 = 0; @@ -182,6 +207,10 @@ test "while on bool with else result follow break prong" { } test "while on optional with else result follow else prong" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const result = while (returnNull()) |value| { break value; } else @as(i32, 2); @@ -189,6 +218,10 @@ test "while on optional with else result follow else prong" { } test "while on optional with else result follow break prong" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const result = while (returnOptional(10)) |value| { break value; } else @as(i32, 2); @@ -215,6 +248,10 @@ fn returnTrue() bool { } test "return with implicit cast from while loop" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + returnWithImplicitCastFromWhileLoopTest() catch unreachable; } fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { @@ -224,6 +261,10 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { } test "while on error union with else result follow else prong" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const result = while (returnError()) |value| { break value; } else |_| @as(i32, 2); @@ -231,6 +272,10 @@ 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_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const result = while (returnSuccess(10)) |value| { break value; } else |_| @as(i32, 2); @@ -253,6 +298,10 @@ test "while bool 2 break statements and an else" { } test "while optional 2 break statements and an else" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + const S = struct { fn entry(opt_t: ?bool, f: bool) !void { var ok = false;