commit e5c30eef1f338ed65325ddbfd4d631baef0d9b81 (tree)
parent b23f10b42403406f40158ec11de95a3f80ce5879
Author: Jakub Konka <kubkon@jakubkonka.com>
Date: Tue, 22 Feb 2022 23:06:07 +0100
Merge pull request #10949 from ziglang/x64-print-results
stage2,x64: print test_runner results
Diffstat:
50 files changed, 1717 insertions(+), 319 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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;
-
- return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
+ 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;
+
+ 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 => {
- 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 => {
+ .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 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;