commit 0f1652dc603ad43be733cfdd721cedf38d9e45d9 (tree)
parent 62a0fbdaef575c857a7fa5f911447dd7275c9f22
Author: Jacob Young <jacobly0@users.noreply.github.com>
Date: Sun, 1 Oct 2023 20:45:42 -0400
Merge pull request #17262 from jacobly0/x86_64
x86_64: support operations that are implemented in compiler_rt
Diffstat:
20 files changed, 1894 insertions(+), 1358 deletions(-)
diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig
@@ -82,7 +82,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?
/// need for extending them to wider fp types.
/// TODO remove this; do this type selection in the language rather than
/// here in compiler-rt.
-pub fn F16T(comptime other_type: type) type {
+pub fn F16T(comptime OtherType: type) type {
return switch (builtin.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => if (std.Target.arm.featureSetHas(builtin.cpu.features, .has_v8))
switch (builtin.abi.floatAbi()) {
@@ -93,7 +93,7 @@ pub fn F16T(comptime other_type: type) type {
u16,
.aarch64, .aarch64_be, .aarch64_32 => f16,
.riscv64 => if (builtin.zig_backend == .stage1) u16 else f16,
- .x86, .x86_64 => if (builtin.target.isDarwin()) switch (other_type) {
+ .x86, .x86_64 => if (builtin.target.isDarwin()) switch (OtherType) {
// Starting with LLVM 16, Darwin uses different abi for f16
// depending on the type of the other return/argument..???
f32, f64 => u16,
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -1871,8 +1871,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
comp.job_queued_compiler_rt_lib = true;
} else if (options.output_mode != .Obj) {
log.debug("queuing a job to build compiler_rt_obj", .{});
- // If build-obj with -fcompiler-rt is requested, that is handled specially
- // elsewhere. In this case we are making a static library, so we ask
+ // In this case we are making a static library, so we ask
// for a compiler-rt object to put in it.
comp.job_queued_compiler_rt_obj = true;
}
diff --git a/src/InternPool.zig b/src/InternPool.zig
@@ -5407,19 +5407,19 @@ pub fn getAnonStructType(ip: *InternPool, gpa: Allocator, ini: AnonStructTypeIni
/// This is equivalent to `Key.FuncType` but adjusted to have a slice for `param_types`.
pub const GetFuncTypeKey = struct {
- param_types: []Index,
+ param_types: []const Index,
return_type: Index,
- comptime_bits: u32,
- noalias_bits: u32,
+ comptime_bits: u32 = 0,
+ noalias_bits: u32 = 0,
/// `null` means generic.
- alignment: ?Alignment,
+ alignment: ?Alignment = .none,
/// `null` means generic.
- cc: ?std.builtin.CallingConvention,
- is_var_args: bool,
- is_generic: bool,
- is_noinline: bool,
- section_is_generic: bool,
- addrspace_is_generic: bool,
+ cc: ?std.builtin.CallingConvention = .Unspecified,
+ is_var_args: bool = false,
+ is_generic: bool = false,
+ is_noinline: bool = false,
+ section_is_generic: bool = false,
+ addrspace_is_generic: bool = false,
};
pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocator.Error!Index {
@@ -5754,15 +5754,10 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
const func_ty = try ip.getFuncType(gpa, .{
.param_types = arg.param_types,
.return_type = arg.bare_return_type,
- .comptime_bits = 0,
.noalias_bits = arg.noalias_bits,
.alignment = arg.alignment,
.cc = arg.cc,
- .is_var_args = false,
- .is_generic = false,
.is_noinline = arg.is_noinline,
- .section_is_generic = false,
- .addrspace_is_generic = false,
});
const generic_owner = unwrapCoercedFunc(ip, arg.generic_owner);
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -7373,10 +7373,10 @@ fn analyzeCall(
const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
const owner_info = mod.typeToFunc(fn_owner_decl.ty).?;
+ const new_param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len);
var new_fn_info: InternPool.GetFuncTypeKey = .{
- .param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len),
+ .param_types = new_param_types,
.return_type = owner_info.return_type,
- .comptime_bits = 0,
.noalias_bits = owner_info.noalias_bits,
.alignment = if (owner_info.align_is_generic) null else owner_info.alignment,
.cc = if (owner_info.cc_is_generic) null else owner_info.cc,
@@ -7403,7 +7403,7 @@ fn analyzeCall(
block,
&child_block,
inst,
- new_fn_info.param_types,
+ new_param_types,
&arg_i,
args_info,
is_comptime_call,
@@ -21144,16 +21144,11 @@ fn zirReify(
const ty = try mod.funcType(.{
.param_types = param_types,
- .comptime_bits = 0,
.noalias_bits = noalias_bits,
.return_type = return_type.toIntern(),
.alignment = alignment,
.cc = cc,
.is_var_args = is_var_args,
- .is_generic = false,
- .is_noinline = false,
- .section_is_generic = false,
- .addrspace_is_generic = false,
});
return Air.internedToRef(ty.toIntern());
},
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
@@ -215,6 +215,7 @@ pub const MCValue = union(enum) {
/// but it has not been spilled there yet in the current control flow.
/// Payload is a frame index.
reserved_frame: FrameIndex,
+ air_ref: Air.Inst.Ref,
fn isMemory(mcv: MCValue) bool {
return switch (mcv) {
@@ -278,6 +279,7 @@ pub const MCValue = union(enum) {
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // not in memory
.memory => |addr| .{ .immediate = addr },
.indirect => |reg_off| switch (reg_off.off) {
@@ -306,6 +308,7 @@ pub const MCValue = union(enum) {
.load_tlv,
.load_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // not dereferenceable
.immediate => |addr| .{ .memory = addr },
.register => |reg| .{ .indirect = .{ .reg = reg } },
@@ -335,6 +338,7 @@ pub const MCValue = union(enum) {
.lea_tlv,
.load_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // not offsettable
.immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
.register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
@@ -366,6 +370,7 @@ pub const MCValue = union(enum) {
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable,
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr })
@@ -405,6 +410,7 @@ pub const MCValue = union(enum) {
.load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
.lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }),
.reserved_frame => |pl| try writer.print("(dead:{})", .{pl}),
+ .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}),
}
}
};
@@ -433,6 +439,7 @@ const InstTracking = struct {
=> result,
.dead,
.reserved_frame,
+ .air_ref,
=> unreachable,
.eflags,
.register,
@@ -491,6 +498,7 @@ const InstTracking = struct {
.register_overflow,
.indirect,
.reserved_frame,
+ .air_ref,
=> unreachable,
};
}
@@ -531,6 +539,7 @@ const InstTracking = struct {
.register_offset,
.register_overflow,
.indirect,
+ .air_ref,
=> unreachable,
}
}
@@ -1807,11 +1816,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.log2,
.log10,
.round,
- => try self.airUnaryMath(inst),
+ => |tag| try self.airUnaryMath(inst, tag),
- .floor => try self.airRound(inst, 0b1_0_01),
- .ceil => try self.airRound(inst, 0b1_0_10),
- .trunc_float => try self.airRound(inst, 0b1_0_11),
+ .floor => try self.airRound(inst, .{ .mode = .down, .precision = .inexact }),
+ .ceil => try self.airRound(inst, .{ .mode = .up, .precision = .inexact }),
+ .trunc_float => try self.airRound(inst, .{ .mode = .zero, .precision = .inexact }),
.sqrt => try self.airSqrt(inst),
.neg => try self.airFloatSign(inst),
@@ -2439,7 +2448,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
}
pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
- const tracking = self.inst_tracking.getPtr(inst).?;
+ const tracking = self.inst_tracking.getPtr(inst) orelse return;
assert(tracking.getReg().?.id() == reg.id());
try tracking.spill(self, inst);
tracking.trackSpill(self, inst);
@@ -2515,63 +2524,96 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
const src_ty = self.typeOf(ty_op.operand);
const src_bits = src_ty.floatBits(self.target.*);
- const src_mcv = try self.resolveInst(ty_op.operand);
- const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
- src_mcv
- else
- try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
- const dst_reg = dst_mcv.getReg().?.to128();
- const dst_lock = self.register_manager.lockReg(dst_reg);
- defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+ const result = result: {
+ if (switch (dst_bits) {
+ 16 => switch (src_bits) {
+ 32 => !self.hasFeature(.f16c),
+ 64, 80, 128 => true,
+ else => unreachable,
+ },
+ 32 => switch (src_bits) {
+ 64 => false,
+ 80, 128 => true,
+ else => unreachable,
+ },
+ 64 => switch (src_bits) {
+ 80, 128 => true,
+ else => unreachable,
+ },
+ 80 => switch (dst_bits) {
+ 128 => true,
+ else => unreachable,
+ },
+ else => unreachable,
+ }) {
+ var callee: ["__trunc?f?f2".len]u8 = undefined;
+ break :result try self.genCall(.{ .lib = .{
+ .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),
+ .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "__trunc{c}f{c}f2", .{
+ floatCompilerRtAbiName(src_bits),
+ floatCompilerRtAbiName(dst_bits),
+ }) catch unreachable,
+ } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
+ }
- if (dst_bits == 16 and self.hasFeature(.f16c)) {
- switch (src_bits) {
- 32 => {
- const mat_src_reg = if (src_mcv.isRegister())
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
+ else
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
+ const dst_reg = dst_mcv.getReg().?.to128();
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ if (dst_bits == 16) {
+ assert(self.hasFeature(.f16c));
+ switch (src_bits) {
+ 32 => {
+ const mat_src_reg = if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv);
+ try self.asmRegisterRegisterImmediate(
+ .{ .v_, .cvtps2ph },
+ dst_reg,
+ mat_src_reg.to128(),
+ Immediate.u(0b1_00),
+ );
+ },
+ else => unreachable,
+ }
+ } else {
+ assert(src_bits == 64 and dst_bits == 32);
+ if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
+ .{ .v_ss, .cvtsd2 },
+ dst_reg,
+ dst_reg,
+ src_mcv.mem(.qword),
+ ) else try self.asmRegisterRegisterRegister(
+ .{ .v_ss, .cvtsd2 },
+ dst_reg,
+ dst_reg,
+ (if (src_mcv.isRegister())
src_mcv.getReg().?
else
- try self.copyToTmpRegister(src_ty, src_mcv);
- try self.asmRegisterRegisterImmediate(
- .{ .v_, .cvtps2ph },
- dst_reg,
- mat_src_reg.to128(),
- Immediate.u(0b1_00),
- );
- },
- else => return self.fail("TODO implement airFptrunc from {} to {}", .{
- src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
- }),
+ try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
+ ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
+ .{ ._ss, .cvtsd2 },
+ dst_reg,
+ src_mcv.mem(.qword),
+ ) else try self.asmRegisterRegister(
+ .{ ._ss, .cvtsd2 },
+ dst_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
+ );
}
- } else if (src_bits == 64 and dst_bits == 32) {
- if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
- .{ .v_ss, .cvtsd2 },
- dst_reg,
- dst_reg,
- src_mcv.mem(.qword),
- ) else try self.asmRegisterRegisterRegister(
- .{ .v_ss, .cvtsd2 },
- dst_reg,
- dst_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
- ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
- .{ ._ss, .cvtsd2 },
- dst_reg,
- src_mcv.mem(.qword),
- ) else try self.asmRegisterRegister(
- .{ ._ss, .cvtsd2 },
- dst_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
- );
- } else return self.fail("TODO implement airFptrunc from {} to {}", .{
- src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
- });
- return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
+ break :result dst_mcv;
+ };
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
@@ -2581,58 +2623,96 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
const src_ty = self.typeOf(ty_op.operand);
const src_bits = src_ty.floatBits(self.target.*);
- const src_mcv = try self.resolveInst(ty_op.operand);
- const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
- src_mcv
- else
- try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
- const dst_reg = dst_mcv.getReg().?.to128();
- const dst_lock = self.register_manager.lockReg(dst_reg);
- defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+ const result = result: {
+ if (switch (src_bits) {
+ 16 => switch (dst_bits) {
+ 32, 64 => !self.hasFeature(.f16c),
+ 80, 128 => true,
+ else => unreachable,
+ },
+ 32 => switch (dst_bits) {
+ 64 => false,
+ 80, 128 => true,
+ else => unreachable,
+ },
+ 64 => switch (dst_bits) {
+ 80, 128 => true,
+ else => unreachable,
+ },
+ 80 => switch (dst_bits) {
+ 128 => true,
+ else => unreachable,
+ },
+ else => unreachable,
+ }) {
+ var callee: ["__extend?f?f2".len]u8 = undefined;
+ break :result try self.genCall(.{ .lib = .{
+ .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),
+ .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "__extend{c}f{c}f2", .{
+ floatCompilerRtAbiName(src_bits),
+ floatCompilerRtAbiName(dst_bits),
+ }) catch unreachable,
+ } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
+ }
- if (src_bits == 16 and self.hasFeature(.f16c)) {
- const mat_src_reg = if (src_mcv.isRegister())
- src_mcv.getReg().?
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ src_mcv
else
- try self.copyToTmpRegister(src_ty, src_mcv);
- try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128());
- switch (dst_bits) {
- 32 => {},
- 64 => try self.asmRegisterRegisterRegister(.{ .v_sd, .cvtss2 }, dst_reg, dst_reg, dst_reg),
- else => return self.fail("TODO implement airFpext from {} to {}", .{
- src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
- }),
- }
- } else if (src_bits == 32 and dst_bits == 64) {
- if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
- .{ .v_sd, .cvtss2 },
- dst_reg,
- dst_reg,
- src_mcv.mem(.dword),
- ) else try self.asmRegisterRegisterRegister(
- .{ .v_sd, .cvtss2 },
- dst_reg,
- dst_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
- ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
- .{ ._sd, .cvtss2 },
- dst_reg,
- src_mcv.mem(.dword),
- ) else try self.asmRegisterRegister(
- .{ ._sd, .cvtss2 },
- dst_reg,
- (if (src_mcv.isRegister())
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
+ const dst_reg = dst_mcv.getReg().?.to128();
+ const dst_lock = self.register_manager.lockReg(dst_reg);
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
+
+ if (src_bits == 16) {
+ assert(self.hasFeature(.f16c));
+ const mat_src_reg = if (src_mcv.isRegister())
src_mcv.getReg().?
else
- try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
- );
- } else return self.fail("TODO implement airFpext from {} to {}", .{
- src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
- });
- return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
+ try self.copyToTmpRegister(src_ty, src_mcv);
+ try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128());
+ switch (dst_bits) {
+ 32 => {},
+ 64 => try self.asmRegisterRegisterRegister(
+ .{ .v_sd, .cvtss2 },
+ dst_reg,
+ dst_reg,
+ dst_reg,
+ ),
+ else => unreachable,
+ }
+ } else {
+ assert(src_bits == 32 and dst_bits == 64);
+ if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
+ .{ .v_sd, .cvtss2 },
+ dst_reg,
+ dst_reg,
+ src_mcv.mem(.dword),
+ ) else try self.asmRegisterRegisterRegister(
+ .{ .v_sd, .cvtss2 },
+ dst_reg,
+ dst_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
+ ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
+ .{ ._sd, .cvtss2 },
+ dst_reg,
+ src_mcv.mem(.dword),
+ ) else try self.asmRegisterRegister(
+ .{ ._sd, .cvtss2 },
+ dst_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
+ );
+ }
+ break :result dst_mcv;
+ };
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
@@ -5002,7 +5082,26 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
return self.floatSign(inst, un_op, ty);
}
-fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
+const RoundMode = packed struct(u5) {
+ mode: enum(u4) {
+ /// Round to nearest (even)
+ nearest = 0b0_00,
+ /// Round down (toward -∞)
+ down = 0b0_01,
+ /// Round up (toward +∞)
+ up = 0b0_10,
+ /// Round toward zero (truncate)
+ zero = 0b0_11,
+ /// Use current rounding mode of MXCSR.RC
+ mxcsr = 0b1_00,
+ },
+ precision: enum(u1) {
+ normal = 0b0,
+ inexact = 0b1,
+ },
+};
+
+fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {
const un_op = self.air.instructions.items(.data)[inst].un_op;
const ty = self.typeOf(un_op);
@@ -5018,12 +5117,9 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
}
-fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4) !void {
+fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void {
const mod = self.bin_file.options.module.?;
- if (!self.hasFeature(.sse4_1))
- return self.fail("TODO implement genRound without sse4_1 feature", .{});
-
- const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
+ const mir_tag = @as(?Mir.Inst.FixedTag, if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) {
.Float => switch (ty.floatBits(self.target.*)) {
32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
@@ -5050,9 +5146,28 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
else => null,
},
else => unreachable,
- }) orelse return self.fail("TODO implement genRound for {}", .{
- ty.fmt(self.bin_file.options.module.?),
- });
+ } else null) orelse {
+ if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement genRound for {}", .{
+ ty.fmt(self.bin_file.options.module.?),
+ });
+
+ var callee: ["__trunc?".len]u8 = undefined;
+ const res = try self.genCall(.{ .lib = .{
+ .return_type = ty.toIntern(),
+ .param_types = &.{ty.toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
+ floatLibcAbiPrefix(ty),
+ switch (mode.mode) {
+ .down => "floor",
+ .up => "ceil",
+ .zero => "trunc",
+ else => unreachable,
+ },
+ floatLibcAbiSuffix(ty),
+ }) catch unreachable,
+ } }, &.{ty}, &.{src_mcv});
+ return self.genSetReg(dst_reg, ty, res);
+ };
const abi_size: u32 = @intCast(ty.abiSize(mod));
const dst_alias = registerAlias(dst_reg, abi_size);
switch (mir_tag[0]) {
@@ -5061,7 +5176,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
dst_alias,
dst_alias,
src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
- Immediate.u(mode),
+ Immediate.u(@as(u5, @bitCast(mode))),
) else try self.asmRegisterRegisterRegisterImmediate(
mir_tag,
dst_alias,
@@ -5070,13 +5185,13 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
src_mcv.getReg().?
else
try self.copyToTmpRegister(ty, src_mcv), abi_size),
- Immediate.u(mode),
+ Immediate.u(@as(u5, @bitCast(mode))),
),
else => if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
mir_tag,
dst_alias,
src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
- Immediate.u(mode),
+ Immediate.u(@as(u5, @bitCast(mode))),
) else try self.asmRegisterRegisterImmediate(
mir_tag,
dst_alias,
@@ -5084,7 +5199,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
src_mcv.getReg().?
else
try self.copyToTmpRegister(ty, src_mcv), abi_size),
- Immediate.u(mode),
+ Immediate.u(@as(u5, @bitCast(mode))),
),
}
}
@@ -5244,9 +5359,21 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
else => unreachable,
},
else => unreachable,
- }) orelse return self.fail("TODO implement airSqrt for {}", .{
- ty.fmt(mod),
- });
+ }) orelse {
+ if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement airSqrt for {}", .{
+ ty.fmt(mod),
+ });
+
+ var callee: ["__sqrt?".len]u8 = undefined;
+ break :result try self.genCall(.{ .lib = .{
+ .return_type = ty.toIntern(),
+ .param_types = &.{ty.toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{
+ floatLibcAbiPrefix(ty),
+ floatLibcAbiSuffix(ty),
+ }) catch unreachable,
+ } }, &.{ty}, &.{src_mcv});
+ };
switch (mir_tag[0]) {
.v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
mir_tag,
@@ -5280,13 +5407,32 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ un_op, .none, .none });
}
-fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
+fn airUnaryMath(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
const un_op = self.air.instructions.items(.data)[inst].un_op;
- _ = un_op;
- return self.fail("TODO implement airUnaryMath for {}", .{
- self.air.instructions.items(.tag)[inst],
- });
- //return self.finishAir(inst, result, .{ un_op, .none, .none });
+ const ty = self.typeOf(un_op);
+ var callee: ["__round?".len]u8 = undefined;
+ const result = try self.genCall(.{ .lib = .{
+ .return_type = ty.toIntern(),
+ .param_types = &.{ty.toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
+ floatLibcAbiPrefix(ty),
+ switch (tag) {
+ .sin,
+ .cos,
+ .tan,
+ .exp,
+ .exp2,
+ .log,
+ .log2,
+ .log10,
+ .round,
+ => @tagName(tag),
+ else => unreachable,
+ },
+ floatLibcAbiSuffix(ty),
+ }) catch unreachable,
+ } }, &.{ty}, &.{.{ .air_ref = un_op }});
+ return self.finishAir(inst, result, .{ un_op, .none, .none });
}
fn reuseOperand(
@@ -5439,6 +5585,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
},
+ .air_ref => |ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ref)),
}
}
@@ -5584,6 +5731,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
},
+ .air_ref => |ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ref)),
}
}
@@ -5925,6 +6073,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // unmodifiable destination
.register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
.memory, .load_got, .load_direct, .load_tlv => {
@@ -6433,6 +6582,34 @@ fn genBinOp(
const lhs_ty = self.typeOf(lhs_air);
const rhs_ty = self.typeOf(rhs_air);
const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));
+
+ if (lhs_ty.isRuntimeFloat() and switch (lhs_ty.floatBits(self.target.*)) {
+ 16 => !self.hasFeature(.f16c),
+ 32, 64 => false,
+ 80, 128 => true,
+ else => unreachable,
+ }) {
+ var callee: ["__add?f3".len]u8 = undefined;
+ return self.genCall(.{ .lib = .{
+ .return_type = lhs_ty.toIntern(),
+ .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
+ .callee = switch (air_tag) {
+ .add, .sub, .mul, .div_float => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{
+ @tagName(air_tag)[0..3],
+ floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)),
+ }),
+ .min, .max => std.fmt.bufPrint(&callee, "{s}f{s}{s}", .{
+ floatLibcAbiPrefix(lhs_ty),
+ @tagName(air_tag),
+ floatLibcAbiSuffix(lhs_ty),
+ }),
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{
+ @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),
+ }),
+ } catch unreachable,
+ } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });
+ }
+
if ((lhs_ty.scalarType(mod).isRuntimeFloat() and
lhs_ty.scalarType(mod).floatBits(self.target.*) == 80) or
lhs_ty.abiSize(mod) > @as(u6, if (self.hasFeature(.avx)) 32 else 16))
@@ -6584,7 +6761,11 @@ fn genBinOp(
.min,
.max,
=> {
- const mat_src_mcv: MCValue = if (switch (src_mcv) {
+ const resolved_src_mcv = switch (src_mcv) {
+ else => src_mcv,
+ .air_ref => |ref| try self.resolveInst(ref),
+ };
+ const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
.immediate,
.eflags,
.register_offset,
@@ -6598,7 +6779,10 @@ fn genBinOp(
=> true,
.memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
else => false,
- }) .{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) } else src_mcv;
+ })
+ .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
+ else
+ resolved_src_mcv;
const mat_mcv_lock = switch (mat_src_mcv) {
.register => |reg| self.register_manager.lockReg(reg),
else => null,
@@ -6645,6 +6829,7 @@ fn genBinOp(
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable,
.register => |src_reg| try self.asmCmovccRegisterRegister(
registerAlias(tmp_reg, cmov_abi_size),
@@ -6685,7 +6870,8 @@ fn genBinOp(
const mir_tag = @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) {
else => unreachable,
.Float => switch (lhs_ty.floatBits(self.target.*)) {
- 16 => if (self.hasFeature(.f16c)) {
+ 16 => {
+ assert(self.hasFeature(.f16c));
const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
defer self.register_manager.unlockReg(tmp_lock);
@@ -6728,7 +6914,7 @@ fn genBinOp(
Immediate.u(0b1_00),
);
return dst_mcv;
- } else null,
+ },
32 => switch (air_tag) {
.add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
.sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub },
@@ -6989,181 +7175,184 @@ fn genBinOp(
else => null,
},
.Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) {
- 16 => if (self.hasFeature(.f16c)) switch (lhs_ty.vectorLen(mod)) {
- 1 => {
- const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
- const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
- defer self.register_manager.unlockReg(tmp_lock);
+ 16 => tag: {
+ assert(self.hasFeature(.f16c));
+ switch (lhs_ty.vectorLen(mod)) {
+ 1 => {
+ const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
- if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
- .{ .vp_w, .insr },
- dst_reg,
- dst_reg,
- src_mcv.mem(.word),
- Immediate.u(1),
- ) else try self.asmRegisterRegisterRegister(
- .{ .vp_, .unpcklwd },
- dst_reg,
- dst_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
- );
- try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
- try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
- try self.asmRegisterRegisterRegister(
- switch (air_tag) {
- .add => .{ .v_ss, .add },
- .sub => .{ .v_ss, .sub },
- .mul => .{ .v_ss, .mul },
- .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ss, .div },
- .max => .{ .v_ss, .max },
- .min => .{ .v_ss, .max },
- else => unreachable,
- },
- dst_reg,
- dst_reg,
- tmp_reg,
- );
- try self.asmRegisterRegisterImmediate(
- .{ .v_, .cvtps2ph },
- dst_reg,
- dst_reg,
- Immediate.u(0b1_00),
- );
- return dst_mcv;
- },
- 2 => {
- const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
- const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
- defer self.register_manager.unlockReg(tmp_lock);
+ if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
+ .{ .vp_w, .insr },
+ dst_reg,
+ dst_reg,
+ src_mcv.mem(.word),
+ Immediate.u(1),
+ ) else try self.asmRegisterRegisterRegister(
+ .{ .vp_, .unpcklwd },
+ dst_reg,
+ dst_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
+ );
+ try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
+ try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
+ try self.asmRegisterRegisterRegister(
+ switch (air_tag) {
+ .add => .{ .v_ss, .add },
+ .sub => .{ .v_ss, .sub },
+ .mul => .{ .v_ss, .mul },
+ .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ss, .div },
+ .max => .{ .v_ss, .max },
+ .min => .{ .v_ss, .max },
+ else => unreachable,
+ },
+ dst_reg,
+ dst_reg,
+ tmp_reg,
+ );
+ try self.asmRegisterRegisterImmediate(
+ .{ .v_, .cvtps2ph },
+ dst_reg,
+ dst_reg,
+ Immediate.u(0b1_00),
+ );
+ return dst_mcv;
+ },
+ 2 => {
+ const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
- if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
- .{ .vp_d, .insr },
- dst_reg,
- src_mcv.mem(.dword),
- Immediate.u(1),
- ) else try self.asmRegisterRegisterRegister(
- .{ .v_ps, .unpckl },
- dst_reg,
- dst_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
- );
- try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
- try self.asmRegisterRegisterRegister(
- .{ .v_ps, .movhl },
- tmp_reg,
- dst_reg,
- dst_reg,
- );
- try self.asmRegisterRegisterRegister(
- switch (air_tag) {
- .add => .{ .v_ps, .add },
- .sub => .{ .v_ps, .sub },
- .mul => .{ .v_ps, .mul },
- .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
- .max => .{ .v_ps, .max },
- .min => .{ .v_ps, .max },
- else => unreachable,
- },
- dst_reg,
- dst_reg,
- tmp_reg,
- );
- try self.asmRegisterRegisterImmediate(
- .{ .v_, .cvtps2ph },
- dst_reg,
- dst_reg,
- Immediate.u(0b1_00),
- );
- return dst_mcv;
- },
- 3...4 => {
- const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
- const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
- defer self.register_manager.unlockReg(tmp_lock);
+ if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
+ .{ .vp_d, .insr },
+ dst_reg,
+ src_mcv.mem(.dword),
+ Immediate.u(1),
+ ) else try self.asmRegisterRegisterRegister(
+ .{ .v_ps, .unpckl },
+ dst_reg,
+ dst_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
+ );
+ try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
+ try self.asmRegisterRegisterRegister(
+ .{ .v_ps, .movhl },
+ tmp_reg,
+ dst_reg,
+ dst_reg,
+ );
+ try self.asmRegisterRegisterRegister(
+ switch (air_tag) {
+ .add => .{ .v_ps, .add },
+ .sub => .{ .v_ps, .sub },
+ .mul => .{ .v_ps, .mul },
+ .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
+ .max => .{ .v_ps, .max },
+ .min => .{ .v_ps, .max },
+ else => unreachable,
+ },
+ dst_reg,
+ dst_reg,
+ tmp_reg,
+ );
+ try self.asmRegisterRegisterImmediate(
+ .{ .v_, .cvtps2ph },
+ dst_reg,
+ dst_reg,
+ Immediate.u(0b1_00),
+ );
+ return dst_mcv;
+ },
+ 3...4 => {
+ const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128();
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
- try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
- if (src_mcv.isMemory()) try self.asmRegisterMemory(
- .{ .v_ps, .cvtph2 },
- tmp_reg,
- src_mcv.mem(.qword),
- ) else try self.asmRegisterRegister(
- .{ .v_ps, .cvtph2 },
- tmp_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
- );
- try self.asmRegisterRegisterRegister(
- switch (air_tag) {
- .add => .{ .v_ps, .add },
- .sub => .{ .v_ps, .sub },
- .mul => .{ .v_ps, .mul },
- .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
- .max => .{ .v_ps, .max },
- .min => .{ .v_ps, .max },
- else => unreachable,
- },
- dst_reg,
- dst_reg,
- tmp_reg,
- );
- try self.asmRegisterRegisterImmediate(
- .{ .v_, .cvtps2ph },
- dst_reg,
- dst_reg,
- Immediate.u(0b1_00),
- );
- return dst_mcv;
- },
- 5...8 => {
- const tmp_reg = (try self.register_manager.allocReg(null, sse)).to256();
- const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
- defer self.register_manager.unlockReg(tmp_lock);
+ try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
+ if (src_mcv.isMemory()) try self.asmRegisterMemory(
+ .{ .v_ps, .cvtph2 },
+ tmp_reg,
+ src_mcv.mem(.qword),
+ ) else try self.asmRegisterRegister(
+ .{ .v_ps, .cvtph2 },
+ tmp_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
+ );
+ try self.asmRegisterRegisterRegister(
+ switch (air_tag) {
+ .add => .{ .v_ps, .add },
+ .sub => .{ .v_ps, .sub },
+ .mul => .{ .v_ps, .mul },
+ .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
+ .max => .{ .v_ps, .max },
+ .min => .{ .v_ps, .max },
+ else => unreachable,
+ },
+ dst_reg,
+ dst_reg,
+ tmp_reg,
+ );
+ try self.asmRegisterRegisterImmediate(
+ .{ .v_, .cvtps2ph },
+ dst_reg,
+ dst_reg,
+ Immediate.u(0b1_00),
+ );
+ return dst_mcv;
+ },
+ 5...8 => {
+ const tmp_reg = (try self.register_manager.allocReg(null, sse)).to256();
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
+ defer self.register_manager.unlockReg(tmp_lock);
- try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), dst_reg);
- if (src_mcv.isMemory()) try self.asmRegisterMemory(
- .{ .v_ps, .cvtph2 },
- tmp_reg,
- src_mcv.mem(.xword),
- ) else try self.asmRegisterRegister(
- .{ .v_ps, .cvtph2 },
- tmp_reg,
- (if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
- );
- try self.asmRegisterRegisterRegister(
- switch (air_tag) {
- .add => .{ .v_ps, .add },
- .sub => .{ .v_ps, .sub },
- .mul => .{ .v_ps, .mul },
- .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
- .max => .{ .v_ps, .max },
- .min => .{ .v_ps, .max },
- else => unreachable,
- },
- dst_reg.to256(),
- dst_reg.to256(),
- tmp_reg,
- );
- try self.asmRegisterRegisterImmediate(
- .{ .v_, .cvtps2ph },
- dst_reg,
- dst_reg.to256(),
- Immediate.u(0b1_00),
- );
- return dst_mcv;
- },
- else => null,
- } else null,
+ try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), dst_reg);
+ if (src_mcv.isMemory()) try self.asmRegisterMemory(
+ .{ .v_ps, .cvtph2 },
+ tmp_reg,
+ src_mcv.mem(.xword),
+ ) else try self.asmRegisterRegister(
+ .{ .v_ps, .cvtph2 },
+ tmp_reg,
+ (if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
+ );
+ try self.asmRegisterRegisterRegister(
+ switch (air_tag) {
+ .add => .{ .v_ps, .add },
+ .sub => .{ .v_ps, .sub },
+ .mul => .{ .v_ps, .mul },
+ .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
+ .max => .{ .v_ps, .max },
+ .min => .{ .v_ps, .max },
+ else => unreachable,
+ },
+ dst_reg.to256(),
+ dst_reg.to256(),
+ tmp_reg,
+ );
+ try self.asmRegisterRegisterImmediate(
+ .{ .v_, .cvtps2ph },
+ dst_reg,
+ dst_reg.to256(),
+ Immediate.u(0b1_00),
+ );
+ return dst_mcv;
+ },
+ else => break :tag null,
+ }
+ },
32 => switch (lhs_ty.vectorLen(mod)) {
1 => switch (air_tag) {
.add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
@@ -7290,18 +7479,16 @@ fn genBinOp(
switch (air_tag) {
.add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},
- .div_trunc, .div_floor => if (self.hasFeature(.sse4_1)) try self.genRound(
+ .div_trunc, .div_floor => try self.genRound(
lhs_ty,
dst_reg,
.{ .register = dst_reg },
- switch (air_tag) {
- .div_trunc => 0b1_0_11,
- .div_floor => 0b1_0_01,
+ .{ .mode = switch (air_tag) {
+ .div_trunc => .zero,
+ .div_floor => .down,
else => unreachable,
- },
- ) else return self.fail("TODO implement genBinOp for {s} {} without sse4_1 feature", .{
- @tagName(air_tag), lhs_ty.fmt(self.bin_file.options.module.?),
- }),
+ }, .precision = .inexact },
+ ),
.bit_and, .bit_or, .xor => {},
.max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {
const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size);
@@ -7558,6 +7745,7 @@ fn genBinOpMir(
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // unmodifiable destination
.register, .register_offset => {
assert(dst_mcv.isRegister());
@@ -7673,6 +7861,7 @@ fn genBinOpMir(
else => unreachable,
}
},
+ .air_ref => |ref| try self.genBinOpMir(mir_tag, ty, dst_mcv, try self.resolveInst(ref)),
}
},
.memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
@@ -7696,13 +7885,18 @@ fn genBinOpMir(
};
defer if (dst_info) |info| self.register_manager.unlockReg(info.addr_lock);
- const src_info: OpInfo = switch (src_mcv) {
+ const resolved_src_mcv = switch (src_mcv) {
+ else => src_mcv,
+ .air_ref => |ref| try self.resolveInst(ref),
+ };
+ const src_info: OpInfo = switch (resolved_src_mcv) {
.none,
.unreach,
.dead,
.undef,
.register_overflow,
.reserved_frame,
+ .air_ref,
=> unreachable,
.immediate,
.register,
@@ -7716,7 +7910,7 @@ fn genBinOpMir(
.lea_frame,
=> null,
.memory, .load_got, .load_direct, .load_tlv => src: {
- switch (src_mcv) {
+ switch (resolved_src_mcv) {
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr))) != null and
math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
break :src null,
@@ -7728,7 +7922,7 @@ fn genBinOpMir(
const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
errdefer self.register_manager.unlockReg(src_addr_lock);
- try self.genSetReg(src_addr_reg, Type.usize, src_mcv.address());
+ try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address());
break :src .{
.addr_reg = src_addr_reg,
.addr_lock = src_addr_lock,
@@ -7775,13 +7969,14 @@ fn genBinOpMir(
else => unreachable,
},
);
- switch (src_mcv) {
+ switch (resolved_src_mcv) {
.none,
.unreach,
.dead,
.undef,
.register_overflow,
.reserved_frame,
+ .air_ref,
=> unreachable,
.register => |src_reg| switch (off) {
0 => try self.asmMemoryRegister(
@@ -7857,7 +8052,7 @@ fn genBinOpMir(
=> {
const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{
.indirect = .{ .reg = info.addr_reg, .off = off },
- } else switch (src_mcv) {
+ } else switch (resolved_src_mcv) {
.eflags,
.register_offset,
.lea_direct,
@@ -7865,7 +8060,7 @@ fn genBinOpMir(
.lea_tlv,
.lea_frame,
=> switch (off) {
- 0 => src_mcv,
+ 0 => resolved_src_mcv,
else => .{ .immediate = 0 },
},
.memory => |addr| .{ .memory = @bitCast(@as(i64, @bitCast(addr)) + off) },
@@ -7910,19 +8105,25 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // unmodifiable destination
.register => |dst_reg| {
const dst_alias = registerAlias(dst_reg, abi_size);
const dst_lock = self.register_manager.lockReg(dst_reg);
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
- switch (src_mcv) {
+ const resolved_src_mcv = switch (src_mcv) {
+ else => src_mcv,
+ .air_ref => |ref| try self.resolveInst(ref),
+ };
+ switch (resolved_src_mcv) {
.none,
.unreach,
.dead,
.undef,
.register_overflow,
.reserved_frame,
+ .air_ref,
=> unreachable,
.register => |src_reg| try self.asmRegisterRegister(
.{ .i_, .mul },
@@ -7938,7 +8139,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
Immediate.s(small),
);
} else {
- const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
+ const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);
return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
}
},
@@ -7954,19 +8155,22 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
=> try self.asmRegisterRegister(
.{ .i_, .mul },
dst_alias,
- registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
+ registerAlias(try self.copyToTmpRegister(dst_ty, resolved_src_mcv), abi_size),
),
.memory, .indirect, .load_frame => try self.asmRegisterMemory(
.{ .i_, .mul },
dst_alias,
- Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (resolved_src_mcv) {
.memory => |addr| .{
.base = .{ .reg = .ds },
.disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse
return self.asmRegisterRegister(
.{ .i_, .mul },
dst_alias,
- registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
+ registerAlias(
+ try self.copyToTmpRegister(dst_ty, resolved_src_mcv),
+ abi_size,
+ ),
),
},
.indirect => |reg_off| .{
@@ -8124,31 +8328,85 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
}
fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
- const mod = self.bin_file.options.module.?;
if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
+
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
- const callee = pl_op.operand;
const extra = self.air.extraData(Air.Call, pl_op.payload);
- const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
- const ty = self.typeOf(callee);
+ const arg_refs: []const Air.Inst.Ref =
+ @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
- const fn_ty = switch (ty.zigTypeTag(mod)) {
- .Fn => ty,
- .Pointer => ty.childType(mod),
- else => unreachable,
+ const ExpectedContents = extern struct {
+ tys: [16][@sizeOf(Type)]u8 align(@alignOf(Type)),
+ vals: [16][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)),
};
+ var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
+ std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
+ const allocator = stack.get();
+
+ const arg_tys = try allocator.alloc(Type, arg_refs.len);
+ defer allocator.free(arg_tys);
+ for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = self.typeOf(arg_ref);
+
+ const arg_vals = try allocator.alloc(MCValue, arg_refs.len);
+ defer allocator.free(arg_vals);
+ for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };
+
+ const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals);
+
+ var bt = self.liveness.iterateBigTomb(inst);
+ self.feed(&bt, pl_op.operand);
+ for (arg_refs) |arg_ref| self.feed(&bt, arg_ref);
+ const result = if (self.liveness.isUnused(inst)) .unreach else ret;
+ return self.finishAirResult(inst, result);
+}
+
+fn genCall(self: *Self, info: union(enum) {
+ air: Air.Inst.Ref,
+ lib: struct {
+ return_type: InternPool.Index,
+ param_types: []const InternPool.Index,
+ lib: ?[]const u8 = null,
+ callee: []const u8,
+ },
+}, arg_types: []const Type, args: []const MCValue) !MCValue {
+ const mod = self.bin_file.options.module.?;
+
+ const fn_ty = switch (info) {
+ .air => |callee| fn_info: {
+ const callee_ty = self.typeOf(callee);
+ break :fn_info switch (callee_ty.zigTypeTag(mod)) {
+ .Fn => callee_ty,
+ .Pointer => callee_ty.childType(mod),
+ else => unreachable,
+ };
+ },
+ .lib => |lib| try mod.funcType(.{
+ .param_types = lib.param_types,
+ .return_type = lib.return_type,
+ .cc = .C,
+ }),
+ };
const fn_info = mod.typeToFunc(fn_ty).?;
- var info = try self.resolveCallingConventionValues(fn_info, args[fn_info.param_types.len..], .call_frame);
- defer info.deinit(self);
+ const ExpectedContents = [16]Type;
+ var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
+ std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
+ const allocator = stack.get();
+
+ const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len);
+ defer allocator.free(var_args);
+ for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
+
+ var call_info =
+ try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);
+ defer call_info.deinit(self);
// We need a properly aligned and sized call frame to be able to call this function.
{
- const needed_call_frame =
- FrameAlloc.init(.{
- .size = info.stack_byte_count,
- .alignment = info.stack_align,
+ const needed_call_frame = FrameAlloc.init(.{
+ .size = call_info.stack_byte_count,
+ .alignment = call_info.stack_align,
});
const frame_allocs_slice = self.frame_allocs.slice();
const stack_frame_size =
@@ -8164,24 +8422,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
// set stack arguments first because this can clobber registers
// also clobber spill arguments as we go
- switch (info.return_value.long) {
+ switch (call_info.return_value.long) {
.none, .unreach => {},
.indirect => |reg_off| try self.spillRegisters(&.{reg_off.reg}),
else => unreachable,
}
- for (args, info.args) |arg, mc_arg| {
- const arg_ty = self.typeOf(arg);
- const arg_mcv = try self.resolveInst(arg);
- switch (mc_arg) {
- .none => {},
- .register => |reg| try self.spillRegisters(&.{reg}),
- .load_frame => try self.genCopy(arg_ty, mc_arg, arg_mcv),
- else => unreachable,
- }
- }
+ for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
+ .none => {},
+ .register => |reg| try self.spillRegisters(&.{reg}),
+ .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),
+ else => unreachable,
+ };
// now we are free to set register arguments
- const ret_lock = switch (info.return_value.long) {
+ const ret_lock = switch (call_info.return_value.long) {
.none, .unreach => null,
.indirect => |reg_off| lock: {
const ret_ty = fn_info.return_type.toType();
@@ -8189,125 +8443,80 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
try self.genSetReg(reg_off.reg, Type.usize, .{
.lea_frame = .{ .index = frame_index, .off = -reg_off.off },
});
- info.return_value.short = .{ .load_frame = .{ .index = frame_index } };
+ call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } };
break :lock self.register_manager.lockRegAssumeUnused(reg_off.reg);
},
else => unreachable,
};
defer if (ret_lock) |lock| self.register_manager.unlockReg(lock);
- for (args, info.args) |arg, mc_arg| {
- const arg_ty = self.typeOf(arg);
- const arg_mcv = try self.resolveInst(arg);
- switch (mc_arg) {
+ for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| {
+ switch (dst_arg) {
.none, .load_frame => {},
- .register => try self.genCopy(arg_ty, mc_arg, arg_mcv),
+ .register => try self.genCopy(arg_ty, dst_arg, src_arg),
else => unreachable,
}
}
// Due to incremental compilation, how function calls are generated depends
// on linking.
- if (try self.air.value(callee, mod)) |func_value| {
- const func_key = mod.intern_pool.indexToKey(func_value.ip_index);
- if (switch (func_key) {
- .func => |func| func.owner_decl,
- .ptr => |ptr| switch (ptr.addr) {
- .decl => |decl| decl,
+ switch (info) {
+ .air => |callee| if (try self.air.value(callee, mod)) |func_value| {
+ const func_key = mod.intern_pool.indexToKey(func_value.ip_index);
+ if (switch (func_key) {
+ .func => |func| func.owner_decl,
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl => |decl| decl,
+ else => null,
+ },
else => null,
- },
- else => null,
- }) |owner_decl| {
- if (self.bin_file.cast(link.File.Elf)) |elf_file| {
- const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
- const sym = elf_file.symbol(sym_index);
- sym.flags.needs_got = true;
- _ = try sym.getOrCreateGotEntry(sym_index, elf_file);
- _ = try self.addInst(.{
- .tag = .call,
- .ops = .direct_got_reloc,
- .data = .{ .reloc = .{
- .atom_index = try self.owner.getSymbolIndex(self),
- .sym_index = sym.esym_index,
- } },
- });
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
- const atom = try coff_file.getOrCreateAtomForDecl(owner_decl);
- const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
- try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
- try self.asmRegister(.{ ._, .call }, .rax);
- } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
- const atom = try macho_file.getOrCreateAtomForDecl(owner_decl);
- const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
- try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
- try self.asmRegister(.{ ._, .call }, .rax);
- } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
- const atom_index = try p9.seeDecl(owner_decl);
- const atom = p9.getAtom(atom_index);
- try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
- .base = .{ .reg = .ds },
- .disp = @intCast(atom.getOffsetTableAddress(p9)),
- }));
- } else unreachable;
- } else if (func_value.getExternFunc(mod)) |extern_func| {
- const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name);
- const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name);
- if (self.bin_file.cast(link.File.Elf)) |elf_file| {
- const atom_index = try self.owner.getSymbolIndex(self);
- const sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name);
- _ = try self.addInst(.{
- .tag = .call,
- .ops = .extern_fn_reloc,
- .data = .{ .reloc = .{
- .atom_index = atom_index,
- .sym_index = sym_index,
- } },
- });
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
- const atom_index = try self.owner.getSymbolIndex(self);
- const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
- _ = try self.addInst(.{
- .tag = .mov,
- .ops = .import_reloc,
- .data = .{ .rx = .{
- .r1 = .rax,
- .payload = try self.addExtra(Mir.Reloc{
- .atom_index = atom_index,
- .sym_index = sym_index,
- }),
- } },
- });
- try self.asmRegister(.{ ._, .call }, .rax);
- } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
- const atom_index = try self.owner.getSymbolIndex(self);
- const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
- _ = try self.addInst(.{
- .tag = .call,
- .ops = .extern_fn_reloc,
- .data = .{ .reloc = .{
- .atom_index = atom_index,
- .sym_index = sym_index,
- } },
- });
+ }) |owner_decl| {
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
+ const sym = elf_file.symbol(sym_index);
+ sym.flags.needs_got = true;
+ _ = try sym.getOrCreateGotEntry(sym_index, elf_file);
+ _ = try self.addInst(.{
+ .tag = .call,
+ .ops = .direct_got_reloc,
+ .data = .{ .reloc = .{
+ .atom_index = try self.owner.getSymbolIndex(self),
+ .sym_index = sym.esym_index,
+ } },
+ });
+ } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
+ const atom = try coff_file.getOrCreateAtomForDecl(owner_decl);
+ const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
+ try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
+ try self.asmRegister(.{ ._, .call }, .rax);
+ } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
+ const atom = try macho_file.getOrCreateAtomForDecl(owner_decl);
+ const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
+ try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
+ try self.asmRegister(.{ ._, .call }, .rax);
+ } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
+ const atom_index = try p9.seeDecl(owner_decl);
+ const atom = p9.getAtom(atom_index);
+ try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
+ .base = .{ .reg = .ds },
+ .disp = @intCast(atom.getOffsetTableAddress(p9)),
+ }));
+ } else unreachable;
+ } else if (func_value.getExternFunc(mod)) |extern_func| {
+ const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name);
+ const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name);
+ try self.genExternSymbolRef(.call, lib_name, decl_name);
} else {
- return self.fail("TODO implement calling extern functions", .{});
+ return self.fail("TODO implement calling bitcasted functions", .{});
}
} else {
- return self.fail("TODO implement calling bitcasted functions", .{});
- }
- } else {
- assert(ty.zigTypeTag(mod) == .Pointer);
- const mcv = try self.resolveInst(callee);
- try self.genSetReg(.rax, Type.usize, mcv);
- try self.asmRegister(.{ ._, .call }, .rax);
+ assert(self.typeOf(callee).zigTypeTag(mod) == .Pointer);
+ try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee });
+ try self.asmRegister(.{ ._, .call }, .rax);
+ },
+ .lib => |lib| try self.genExternSymbolRef(.call, lib.lib, lib.callee),
}
-
- var bt = self.liveness.iterateBigTomb(inst);
- self.feed(&bt, callee);
- for (args) |arg| self.feed(&bt, arg);
-
- const result = if (self.liveness.isUnused(inst)) .unreach else info.return_value.short;
- return self.finishAirResult(inst, result);
+ return call_info.return_value.short;
}
fn airRet(self: *Self, inst: Air.Inst.Index) !void {
@@ -8357,26 +8566,64 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const ty = self.typeOf(bin_op.lhs);
- try self.spillEflagsIfOccupied();
- self.eflags_inst = inst;
+ const result: Condition = result: {
+ switch (ty.zigTypeTag(mod)) {
+ .Float => {
+ const float_bits = ty.floatBits(self.target.*);
+ if (switch (float_bits) {
+ 16 => !self.hasFeature(.f16c),
+ 32, 64 => false,
+ 80, 128 => true,
+ else => unreachable,
+ }) {
+ var callee: ["__???f2".len]u8 = undefined;
+ const ret = try self.genCall(.{ .lib = .{
+ .return_type = .i32_type,
+ .param_types = &.{ ty.toIntern(), ty.toIntern() },
+ .callee = std.fmt.bufPrint(&callee, "__{s}{c}f2", .{
+ switch (op) {
+ .eq => "eq",
+ .neq => "ne",
+ .lt => "lt",
+ .lte => "le",
+ .gt => "gt",
+ .gte => "ge",
+ },
+ floatCompilerRtAbiName(float_bits),
+ }) catch unreachable,
+ } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } });
+ try self.genBinOpMir(.{ ._, .@"test" }, Type.i32, ret, ret);
+ break :result switch (op) {
+ .eq => .e,
+ .neq => .ne,
+ .lt => .l,
+ .lte => .le,
+ .gt => .g,
+ .gte => .ge,
+ };
+ }
+ },
+ else => {},
+ }
- const lhs_mcv = try self.resolveInst(bin_op.lhs);
- const lhs_lock = switch (lhs_mcv) {
- .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
- else => null,
- };
- defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
+ try self.spillEflagsIfOccupied();
- const rhs_mcv = try self.resolveInst(bin_op.rhs);
- const rhs_lock = switch (rhs_mcv) {
- .register => |reg| self.register_manager.lockReg(reg),
- else => null,
- };
- defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
+ const lhs_mcv = try self.resolveInst(bin_op.lhs);
+ const lhs_lock = switch (lhs_mcv) {
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
+ else => null,
+ };
+ defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
+
+ const rhs_mcv = try self.resolveInst(bin_op.rhs);
+ const rhs_lock = switch (rhs_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
- const result = MCValue{
- .eflags = switch (ty.zigTypeTag(mod)) {
- else => result: {
+ switch (ty.zigTypeTag(mod)) {
+ else => {
const abi_size: u16 = @intCast(ty.abiSize(mod));
const may_flip: enum {
may_flip,
@@ -8478,7 +8725,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
},
);
},
- .Float => result: {
+ .Float => {
const flipped = switch (op) {
.lt, .lte => true,
.eq, .gte, .gt, .neq => false,
@@ -8494,7 +8741,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
switch (ty.floatBits(self.target.*)) {
- 16 => if (self.hasFeature(.f16c)) {
+ 16 => {
+ assert(self.hasFeature(.f16c));
const tmp1_reg = (try self.register_manager.allocReg(null, sse)).to128();
const tmp1_mcv = MCValue{ .register = tmp1_reg };
const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);
@@ -8523,9 +8771,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, tmp1_reg, tmp1_reg);
try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg);
try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv);
- } else return self.fail("TODO implement airCmp for {}", .{
- ty.fmt(mod),
- }),
+ },
32 => try self.genBinOpMir(
.{ ._ss, .ucomi },
ty,
@@ -8538,9 +8784,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
.{ .register = dst_reg },
src_mcv,
),
- else => return self.fail("TODO implement airCmp for {}", .{
- ty.fmt(mod),
- }),
+ else => unreachable,
}
break :result switch (if (flipped) op.reverse() else op) {
@@ -8551,9 +8795,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
.neq => .nz_or_p,
};
},
- },
+ }
};
- return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
+
+ self.eflags_inst = inst;
+ return self.finishAir(inst, .{ .eflags = result }, .{ bin_op.lhs, bin_op.rhs, .none });
}
fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
@@ -8571,7 +8817,6 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
try self.spillEflagsIfOccupied();
- self.eflags_inst = inst;
const op_ty = self.typeOf(un_op);
const op_abi_size: u32 = @intCast(op_ty.abiSize(mod));
@@ -8585,8 +8830,9 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
registerAlias(dst_reg, op_abi_size),
Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = .{ .reg = addr_reg } }),
);
- const result = MCValue{ .eflags = .b };
- return self.finishAir(inst, result, .{ un_op, .none, .none });
+
+ self.eflags_inst = inst;
+ return self.finishAir(inst, .{ .eflags = .b }, .{ un_op, .none, .none });
}
fn airTry(self: *Self, inst: Air.Inst.Index) !void {
@@ -8776,7 +9022,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
}
try self.spillEflagsIfOccupied();
- self.eflags_inst = inst;
const pl_ty = opt_ty.optionalChild(mod);
@@ -8785,6 +9030,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
else
.{ .off = @intCast(pl_ty.abiSize(mod)), .ty = Type.bool };
+ self.eflags_inst = inst;
switch (opt_mcv) {
.none,
.unreach,
@@ -8799,6 +9045,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable,
.register => |opt_reg| {
@@ -8866,7 +9113,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue {
const mod = self.bin_file.options.module.?;
try self.spillEflagsIfOccupied();
- self.eflags_inst = inst;
const opt_ty = ptr_ty.childType(mod);
const pl_ty = opt_ty.optionalChild(mod);
@@ -8892,6 +9138,8 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue)
}),
Immediate.u(0),
);
+
+ self.eflags_inst = inst;
return .{ .eflags = .e };
}
@@ -8904,9 +9152,6 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
}
try self.spillEflagsIfOccupied();
- if (maybe_inst) |inst| {
- self.eflags_inst = inst;
- }
const err_off = errUnionErrorOffset(ty.errorUnionPayload(mod), mod);
switch (operand) {
@@ -8944,6 +9189,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
else => return self.fail("TODO implement isErr for {}", .{operand}),
}
+ if (maybe_inst) |inst| self.eflags_inst = inst;
return MCValue{ .eflags = .a };
}
@@ -9825,6 +10071,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
.lea_tlv,
.lea_frame,
.reserved_frame,
+ .air_ref,
=> unreachable, // unmodifiable destination
.register => |reg| try self.genSetReg(reg, ty, src_mcv),
.register_offset => |dst_reg_off| try self.genSetReg(dst_reg_off.reg, ty, switch (src_mcv) {
@@ -10150,6 +10397,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
@tagName(self.bin_file.tag),
});
},
+ .air_ref => |ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(ref)),
}
}
@@ -10262,6 +10510,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
},
else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }),
},
+ .air_ref => |ref| try self.genSetMem(base, disp, ty, try self.resolveInst(ref)),
}
}
@@ -10281,6 +10530,51 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
try self.asmOpOnly(.{ .@"rep _sb", .sto });
}
+fn genExternSymbolRef(
+ self: *Self,
+ comptime tag: Mir.Inst.Tag,
+ lib: ?[]const u8,
+ callee: []const u8,
+) InnerError!void {
+ const atom_index = try self.owner.getSymbolIndex(self);
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ _ = try self.addInst(.{
+ .tag = tag,
+ .ops = .extern_fn_reloc,
+ .data = .{ .reloc = .{
+ .atom_index = atom_index,
+ .sym_index = try elf_file.getGlobalSymbol(callee, lib),
+ } },
+ });
+ } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
+ _ = try self.addInst(.{
+ .tag = .mov,
+ .ops = .import_reloc,
+ .data = .{ .rx = .{
+ .r1 = .rax,
+ .payload = try self.addExtra(Mir.Reloc{
+ .atom_index = atom_index,
+ .sym_index = try coff_file.getGlobalSymbol(callee, lib),
+ }),
+ } },
+ });
+ switch (tag) {
+ .mov => {},
+ .call => try self.asmRegister(.{ ._, .call }, .rax),
+ else => unreachable,
+ }
+ } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
+ _ = try self.addInst(.{
+ .tag = .call,
+ .ops = .extern_fn_reloc,
+ .data = .{ .reloc = .{
+ .atom_index = atom_index,
+ .sym_index = try macho_file.getGlobalSymbol(callee, lib),
+ } },
+ });
+ } else return self.fail("TODO implement calling extern functions", .{});
+}
+
fn genLazySymbolRef(
self: *Self,
comptime tag: Mir.Inst.Tag,
@@ -10480,106 +10774,150 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
const mod = self.bin_file.options.module.?;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const dst_ty = self.typeOfIndex(inst);
+ const dst_bits = dst_ty.floatBits(self.target.*);
+
const src_ty = self.typeOf(ty_op.operand);
const src_bits: u32 = @intCast(src_ty.bitSize(mod));
const src_signedness =
if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned;
- const dst_ty = self.typeOfIndex(inst);
-
const src_size = math.divCeil(u32, @max(switch (src_signedness) {
.signed => src_bits,
.unsigned => src_bits + 1,
}, 32), 8) catch unreachable;
- if (src_size > 8) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
- src_ty.fmt(mod), dst_ty.fmt(mod),
- });
- const src_mcv = try self.resolveInst(ty_op.operand);
- const src_reg = if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(src_ty, src_mcv);
- const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
- defer self.register_manager.unlockReg(src_lock);
+ const result = result: {
+ if (switch (dst_bits) {
+ 16, 80, 128 => true,
+ 32, 64 => src_size > 8 and src_size < 16,
+ else => unreachable,
+ }) {
+ var callee: ["__floatun?i?f".len]u8 = undefined;
+ break :result try self.genCall(.{ .lib = .{
+ .return_type = dst_ty.toIntern(),
+ .param_types = &.{src_ty.toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "__float{s}{c}i{c}f", .{
+ switch (src_signedness) {
+ .signed => "",
+ .unsigned => "un",
+ },
+ intCompilerRtAbiName(src_bits),
+ floatCompilerRtAbiName(dst_bits),
+ }) catch unreachable,
+ } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
+ }
- if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);
+ if (src_size > 8) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
+ src_ty.fmt(mod), dst_ty.fmt(mod),
+ });
- const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));
- const dst_mcv = MCValue{ .register = dst_reg };
- const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
- defer self.register_manager.unlockReg(dst_lock);
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_reg = if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv);
+ const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
+ defer self.register_manager.unlockReg(src_lock);
- const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag(mod)) {
- .Float => switch (dst_ty.floatBits(self.target.*)) {
- 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 },
- 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 },
- 16, 80, 128 => null,
- else => unreachable,
- },
- else => null,
- }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{
- src_ty.fmt(mod), dst_ty.fmt(mod),
- });
- const dst_alias = dst_reg.to128();
- const src_alias = registerAlias(src_reg, src_size);
- switch (mir_tag[0]) {
- .v_ss, .v_sd => try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, src_alias),
- else => try self.asmRegisterRegister(mir_tag, dst_alias, src_alias),
- }
+ if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);
- return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
+ const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));
+ const dst_mcv = MCValue{ .register = dst_reg };
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag(mod)) {
+ .Float => switch (dst_ty.floatBits(self.target.*)) {
+ 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 },
+ 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 },
+ 16, 80, 128 => null,
+ else => unreachable,
+ },
+ else => null,
+ }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{
+ src_ty.fmt(mod), dst_ty.fmt(mod),
+ });
+ const dst_alias = dst_reg.to128();
+ const src_alias = registerAlias(src_reg, src_size);
+ switch (mir_tag[0]) {
+ .v_ss, .v_sd => try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, src_alias),
+ else => try self.asmRegisterRegister(mir_tag, dst_alias, src_alias),
+ }
+
+ break :result dst_mcv;
+ };
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
const mod = self.bin_file.options.module.?;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const src_ty = self.typeOf(ty_op.operand);
const dst_ty = self.typeOfIndex(inst);
const dst_bits: u32 = @intCast(dst_ty.bitSize(mod));
const dst_signedness =
if (dst_ty.isAbiInt(mod)) dst_ty.intInfo(mod).signedness else .unsigned;
-
const dst_size = math.divCeil(u32, @max(switch (dst_signedness) {
.signed => dst_bits,
.unsigned => dst_bits + 1,
}, 32), 8) catch unreachable;
- if (dst_size > 8) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
- src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
- });
- const src_mcv = try self.resolveInst(ty_op.operand);
- const src_reg = if (src_mcv.isRegister())
- src_mcv.getReg().?
- else
- try self.copyToTmpRegister(src_ty, src_mcv);
- const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
- defer self.register_manager.unlockReg(src_lock);
+ const src_ty = self.typeOf(ty_op.operand);
+ const src_bits = src_ty.floatBits(self.target.*);
- const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));
- const dst_mcv = MCValue{ .register = dst_reg };
- const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
- defer self.register_manager.unlockReg(dst_lock);
+ const result = result: {
+ if (switch (src_bits) {
+ 16, 80, 128 => true,
+ 32, 64 => dst_size > 8 and dst_size < 16,
+ else => unreachable,
+ }) {
+ var callee: ["__fixuns?f?i".len]u8 = undefined;
+ break :result try self.genCall(.{ .lib = .{
+ .return_type = dst_ty.toIntern(),
+ .param_types = &.{src_ty.toIntern()},
+ .callee = std.fmt.bufPrint(&callee, "__fix{s}{c}f{c}i", .{
+ switch (dst_signedness) {
+ .signed => "",
+ .unsigned => "uns",
+ },
+ floatCompilerRtAbiName(src_bits),
+ intCompilerRtAbiName(dst_bits),
+ }) catch unreachable,
+ } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
+ }
- try self.asmRegisterRegister(
- @as(?Mir.Inst.FixedTag, switch (src_ty.zigTypeTag(mod)) {
- .Float => switch (src_ty.floatBits(self.target.*)) {
+ if (dst_size > 8) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
+ src_ty.fmt(mod), dst_ty.fmt(mod),
+ });
+
+ const src_mcv = try self.resolveInst(ty_op.operand);
+ const src_reg = if (src_mcv.isRegister())
+ src_mcv.getReg().?
+ else
+ try self.copyToTmpRegister(src_ty, src_mcv);
+ const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
+ defer self.register_manager.unlockReg(src_lock);
+
+ const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod));
+ const dst_mcv = MCValue{ .register = dst_reg };
+ const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
+ defer self.register_manager.unlockReg(dst_lock);
+
+ try self.asmRegisterRegister(
+ switch (src_bits) {
32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si },
64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si },
- 16, 80, 128 => null,
else => unreachable,
},
- else => null,
- }) orelse return self.fail("TODO implement airIntFromFloat from {} to {}", .{
- src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
- }),
- registerAlias(dst_reg, dst_size),
- src_reg.to128(),
- );
+ registerAlias(dst_reg, dst_size),
+ src_reg.to128(),
+ );
- if (dst_bits < dst_size * 8) try self.truncateRegister(dst_ty, dst_reg);
+ if (dst_bits < dst_size * 8) try self.truncateRegister(dst_ty, dst_reg);
- return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
+ break :result dst_mcv;
+ };
+ return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
@@ -11906,7 +12244,7 @@ const CallMCValues = struct {
fn resolveCallingConventionValues(
self: *Self,
fn_info: InternPool.Key.FuncType,
- var_args: []const Air.Inst.Ref,
+ var_args: []const Type,
stack_frame_base: FrameIndex,
) !CallMCValues {
const mod = self.bin_file.options.module.?;
@@ -11919,9 +12257,7 @@ fn resolveCallingConventionValues(
dest.* = src.toType();
}
// TODO: promote var arg types
- for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg| {
- param_ty.* = self.typeOf(arg);
- }
+ for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| param_ty.* = arg_ty;
var result: CallMCValues = .{
.args = try self.gpa.alloc(MCValue, param_types.len),
@@ -12230,3 +12566,52 @@ fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type {
const mod = self.bin_file.options.module.?;
return self.air.typeOfIndex(inst, &mod.intern_pool);
}
+
+fn intCompilerRtAbiName(int_bits: u32) u8 {
+ return switch (int_bits) {
+ 1...32 => 's',
+ 33...64 => 'd',
+ 65...128 => 't',
+ else => unreachable,
+ };
+}
+
+fn floatCompilerRtAbiName(float_bits: u32) u8 {
+ return switch (float_bits) {
+ 16 => 'h',
+ 32 => 's',
+ 64 => 'd',
+ 80 => 'x',
+ 128 => 't',
+ else => unreachable,
+ };
+}
+
+fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type {
+ if (ty.toIntern() == .f16_type and
+ (other_ty.toIntern() == .f32_type or other_ty.toIntern() == .f64_type) and
+ self.target.isDarwin()) return Type.u16;
+ return ty;
+}
+
+fn floatLibcAbiPrefix(ty: Type) []const u8 {
+ return switch (ty.toIntern()) {
+ .f16_type,
+ .f80_type,
+ => "__",
+ .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",
+ else => unreachable,
+ };
+}
+
+fn floatLibcAbiSuffix(ty: Type) []const u8 {
+ return switch (ty.toIntern()) {
+ .f16_type => "h",
+ .f32_type => "f",
+ .f64_type => "",
+ .f80_type => "x",
+ .f128_type => "q",
+ .c_longdouble_type => "l",
+ else => unreachable,
+ };
+}
diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig
@@ -444,7 +444,7 @@ pub const SysV = struct {
/// These registers need to be preserved (saved on the stack) and restored by the caller before
/// the caller relinquishes control to a subroutine via call instruction (or similar).
/// In other words, these registers are free to use by the callee.
- pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
+ pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
@@ -457,7 +457,7 @@ pub const Win64 = struct {
/// These registers need to be preserved (saved on the stack) and restored by the caller before
/// the caller relinquishes control to a subroutine via call instruction (or similar).
/// In other words, these registers are free to use by the callee.
- pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 };
+ pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ sse_avx_regs;
pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
pub const c_abi_int_return_regs = [_]Register{.rax};
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -6394,15 +6394,6 @@ pub const FuncGen = struct {
const fn_ty = try mod.funcType(.{
.param_types = &.{},
.return_type = .void_type,
- .alignment = .none,
- .noalias_bits = 0,
- .comptime_bits = 0,
- .cc = .Unspecified,
- .is_var_args = false,
- .is_generic = false,
- .is_noinline = false,
- .section_is_generic = false,
- .addrspace_is_generic = false,
});
const fn_di_ty = try o.lowerDebugType(fn_ty, .full);
const subprogram = dib.createFunction(
diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig
@@ -86,9 +86,10 @@ test "@abs floats" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
try comptime testAbsFloats(f16);
- if (builtin.zig_backend != .stage2_x86_64) try testAbsFloats(f16);
+ try testAbsFloats(f16);
try comptime testAbsFloats(f32);
try testAbsFloats(f32);
try comptime testAbsFloats(f64);
diff --git a/test/behavior/asm.zig b/test/behavior/asm.zig
@@ -85,7 +85,6 @@ test "alternative constraints" {
test "sized integer/float in asm input" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -137,7 +136,6 @@ test "sized integer/float in asm input" {
test "struct/array/union types as input values" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig
@@ -470,7 +470,6 @@ test "@bitCast of packed struct of bools all true" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -492,7 +491,6 @@ test "@bitCast of packed struct of bools all false" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/bugs/12680.zig b/test/behavior/bugs/12680.zig
@@ -9,9 +9,10 @@ test "export a function twice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) 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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
if (builtin.os.tag == .macos and builtin.zig_backend == .stage2_c) {
// TODO: test.c: error: aliases are not supported on darwin
return error.SkipZigTest;
diff --git a/test/behavior/bugs/529.zig b/test/behavior/bugs/529.zig
@@ -11,11 +11,11 @@ comptime {
const builtin = @import("builtin");
test "issue 529 fixed" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
@import("529_other_file.zig").issue529(null);
issue529(null);
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
@@ -1611,7 +1611,6 @@ test "coercion from single-item pointer to @as to slice" {
test "peer type resolution: const sentinel slice and mutable non-sentinel slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1664,7 +1663,6 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
test "peer type resolution: same array type with sentinel" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1687,7 +1685,6 @@ test "peer type resolution: same array type with sentinel" {
test "peer type resolution: array with sentinel and array without sentinel" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1710,7 +1707,6 @@ test "peer type resolution: array with sentinel and array without sentinel" {
test "peer type resolution: array and vector with same child type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1756,7 +1752,6 @@ test "peer type resolution: array with smaller child type and vector with larger
test "peer type resolution: error union and optional of same type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1780,7 +1775,6 @@ test "peer type resolution: error union and optional of same type" {
test "peer type resolution: C pointer and @TypeOf(null)" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1803,7 +1797,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {
test "peer type resolution: three-way resolution combines error set and optional" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1846,7 +1839,6 @@ test "peer type resolution: three-way resolution combines error set and optional
test "peer type resolution: vector and optional vector" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1869,7 +1861,6 @@ test "peer type resolution: vector and optional vector" {
test "peer type resolution: optional fixed-width int and comptime_int" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1892,7 +1883,6 @@ test "peer type resolution: optional fixed-width int and comptime_int" {
test "peer type resolution: array and tuple" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1916,7 +1906,6 @@ test "peer type resolution: array and tuple" {
test "peer type resolution: vector and tuple" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1940,7 +1929,6 @@ test "peer type resolution: vector and tuple" {
test "peer type resolution: vector and array and tuple" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1983,7 +1971,6 @@ test "peer type resolution: vector and array and tuple" {
test "peer type resolution: empty tuple pointer and slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2005,7 +1992,6 @@ test "peer type resolution: empty tuple pointer and slice" {
test "peer type resolution: tuple pointer and slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2027,7 +2013,6 @@ test "peer type resolution: tuple pointer and slice" {
test "peer type resolution: tuple pointer and optional slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2049,7 +2034,6 @@ test "peer type resolution: tuple pointer and optional slice" {
test "peer type resolution: many compatible pointers" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2116,7 +2100,6 @@ test "peer type resolution: many compatible pointers" {
test "peer type resolution: tuples with comptime fields" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2149,7 +2132,6 @@ test "peer type resolution: tuples with comptime fields" {
test "peer type resolution: C pointer and many pointer" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2173,7 +2155,6 @@ test "peer type resolution: C pointer and many pointer" {
test "peer type resolution: pointer attributes are combined correctly" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2218,7 +2199,6 @@ test "peer type resolution: pointer attributes are combined correctly" {
test "cast builtins can wrap result in optional" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2258,7 +2238,6 @@ test "cast builtins can wrap result in optional" {
test "cast builtins can wrap result in error union" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -2298,7 +2277,6 @@ test "cast builtins can wrap result in error union" {
test "cast builtins can wrap result in error union and optional" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -2496,7 +2474,6 @@ test "@as does not corrupt values with incompatible representations" {
test "result information is preserved through many nested structures" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig
@@ -133,7 +133,6 @@ test "errdefer with payload" {
}
test "reference to errdefer payload" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig
@@ -2,16 +2,8 @@ const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
const math = std.math;
-const pi = std.math.pi;
-const e = std.math.e;
-const has_f80_rt = switch (builtin.cpu.arch) {
- .x86_64, .x86 => true,
- else => false,
-};
-const no_x86_64_hardware_f16_support = builtin.zig_backend == .stage2_x86_64 and
- !std.Target.x86.featureSetHas(builtin.cpu.features, .f16c);
-
-const epsilon_16 = 0.001;
+
+const epsilon_16 = 0.002;
const epsilon = 0.000001;
fn epsForType(comptime T: type) T {
@@ -21,44 +13,195 @@ fn epsForType(comptime T: type) T {
};
}
-test "floating point comparisons" {
+test "add f16" {
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testAdd(f16);
+ try comptime testAdd(f16);
+}
+
+test "add f32/f64" {
+ try testAdd(f32);
+ try comptime testAdd(f32);
+ try testAdd(f64);
+ try comptime testAdd(f64);
+}
+
+test "add f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testAdd(f80);
+ try comptime testAdd(f80);
+ try testAdd(f128);
+ try comptime testAdd(f128);
+ try testAdd(c_longdouble);
+ try comptime testAdd(c_longdouble);
+}
+
+fn testAdd(comptime T: type) !void {
+ var one_point_two_five: T = 1.25;
+ var two_point_seven_five: T = 2.75;
+ try expect(one_point_two_five + two_point_seven_five == 4);
+}
+
+test "sub f16" {
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testSub(f16);
+ try comptime testSub(f16);
+}
+
+test "sub f32/f64" {
+ try testSub(f32);
+ try comptime testSub(f32);
+ try testSub(f64);
+ try comptime testSub(f64);
+}
+
+test "sub f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testSub(f80);
+ try comptime testSub(f80);
+ try testSub(f128);
+ try comptime testSub(f128);
+ try testSub(c_longdouble);
+ try comptime testSub(c_longdouble);
+}
+
+fn testSub(comptime T: type) !void {
+ var one_point_two_five: T = 1.25;
+ var two_point_seven_five: T = 2.75;
+ try expect(one_point_two_five - two_point_seven_five == -1.5);
+}
+
+test "mul f16" {
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testMul(f16);
+ try comptime testMul(f16);
+}
+
+test "mul f32/f64" {
+ try testMul(f32);
+ try comptime testMul(f32);
+ try testMul(f64);
+ try comptime testMul(f64);
+}
+
+test "mul f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testMul(f80);
+ try comptime testMul(f80);
+ try testMul(f128);
+ try comptime testMul(f128);
+ try testMul(c_longdouble);
+ try comptime testMul(c_longdouble);
+}
+
+fn testMul(comptime T: type) !void {
+ var one_point_two_five: T = 1.25;
+ var two_point_seven_five: T = 2.75;
+ try expect(one_point_two_five * two_point_seven_five == 3.4375);
+}
+
+test "cmp f16" {
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testCmp(f16);
+ try comptime testCmp(f16);
+}
+
+test "cmp f32/f64" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try testFloatComparisons();
- try comptime testFloatComparisons();
+ try testCmp(f32);
+ try comptime testCmp(f32);
+ try testCmp(f64);
+ try comptime testCmp(f64);
}
-fn testFloatComparisons() !void {
- inline for ([_]type{ f16, f32, f64, f128 }) |ty| {
+test "cmp f128" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testCmp(f128);
+ try comptime testCmp(f128);
+}
+
+test "cmp f80/c_longdouble" {
+ if (true) return error.SkipZigTest;
+
+ try testCmp(f80);
+ try comptime testCmp(f80);
+ try testCmp(c_longdouble);
+ try comptime testCmp(c_longdouble);
+}
+
+fn testCmp(comptime T: type) !void {
+ {
// No decimal part
- {
- const x: ty = 1.0;
- try expect(x == 1);
- try expect(x != 0);
- try expect(x > 0);
- try expect(x < 2);
- try expect(x >= 1);
- try expect(x <= 1);
- }
+ var x: T = 1.0;
+ try expect(x == 1.0);
+ try expect(x != 0.0);
+ try expect(x > 0.0);
+ try expect(x < 2.0);
+ try expect(x >= 1.0);
+ try expect(x <= 1.0);
+ }
+ {
// Non-zero decimal part
- {
- const x: ty = 1.5;
- try expect(x != 1);
- try expect(x != 2);
- try expect(x > 1);
- try expect(x < 2);
- try expect(x >= 1);
- try expect(x <= 2);
+ var x: T = 1.5;
+ try expect(x != 1.0);
+ try expect(x != 2.0);
+ try expect(x > 1.0);
+ try expect(x < 2.0);
+ try expect(x >= 1.0);
+ try expect(x <= 2.0);
+ }
+
+ @setEvalBranchQuota(2_000);
+ var edges = [_]T{
+ -math.inf(T),
+ -math.floatMax(T),
+ -math.floatMin(T),
+ -math.floatTrueMin(T),
+ -0.0,
+ math.nan(T),
+ 0.0,
+ math.floatTrueMin(T),
+ math.floatMin(T),
+ math.floatMax(T),
+ math.inf(T),
+ };
+ for (edges, 0..) |rhs, rhs_i| {
+ for (edges, 0..) |lhs, lhs_i| {
+ const no_nan = lhs_i != 5 and rhs_i != 5;
+ const lhs_order = if (lhs_i < 5) lhs_i else lhs_i - 2;
+ const rhs_order = if (rhs_i < 5) rhs_i else rhs_i - 2;
+ try expect((lhs == rhs) == (no_nan and lhs_order == rhs_order));
+ try expect((lhs != rhs) == !(no_nan and lhs_order == rhs_order));
+ try expect((lhs < rhs) == (no_nan and lhs_order < rhs_order));
+ try expect((lhs > rhs) == (no_nan and lhs_order > rhs_order));
+ try expect((lhs <= rhs) == (no_nan and lhs_order <= rhs_order));
+ try expect((lhs >= rhs) == (no_nan and lhs_order >= rhs_order));
}
}
}
test "different sized float comparisons" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
try testDifferentSizedFloatComparisons();
try comptime testDifferentSizedFloatComparisons();
@@ -70,27 +213,6 @@ fn testDifferentSizedFloatComparisons() !void {
try expect(a < b);
}
-test "f80 comparisons" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- try expect(compareF80(0.0, .eq, -0.0));
- try expect(compareF80(0.0, .lte, -0.0));
- try expect(compareF80(0.0, .gte, -0.0));
- try expect(compareF80(1.0, .neq, -1.0));
- try expect(compareF80(2.0, .lt, 4.0));
- try expect(compareF80(2.0, .lte, 4.0));
- try expect(compareF80(-2.0, .gt, -4.0));
- try expect(compareF80(-2.0, .gte, -4.0));
-}
-
-fn compareF80(x: f80, op: math.CompareOperator, y: f80) bool {
- return math.compare(x, op, y);
-}
-
// TODO This is waiting on library support for the Windows build (not sure why the other's don't need it)
//test "@nearbyint" {
// comptime testNearbyInt();
@@ -119,42 +241,93 @@ test "negative f128 intFromFloat at compile-time" {
try expect(@as(i64, -2) == b);
}
-test "@sqrt" {
+test "@sqrt f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testSqrt();
- try testSqrt();
+ try testSqrt(f16);
+ try comptime testSqrt(f16);
}
-fn testSqrt() !void {
- try expect(@sqrt(@as(f16, 4)) == 2);
- try expect(@sqrt(@as(f32, 9)) == 3);
- try expect(@sqrt(@as(f64, 25)) == 5);
- try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));
- try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));
+test "@sqrt f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- if (false) {
- if (has_f80_rt) {
- // TODO https://github.com/ziglang/zig/issues/10875
- if (builtin.os.tag != .freebsd) {
- var a: f80 = 25;
- try expect(@sqrt(a) == 5);
- }
- }
- {
- const a: comptime_float = 25.0;
- try expect(@sqrt(a) == 5.0);
- }
- // TODO test f128, and c_longdouble
- // https://github.com/ziglang/zig/issues/4026
- //{
- // var a: f128 = 49;
- //try expect(@sqrt(a) == 7);
- //}
+ try testSqrt(f32);
+ try comptime testSqrt(f32);
+ try testSqrt(f64);
+ try comptime testSqrt(f64);
+}
+
+test "@sqrt f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ if (builtin.os.tag == .freebsd) {
+ // TODO https://github.com/ziglang/zig/issues/10875
+ return error.SkipZigTest;
}
+
+ try testSqrt(f80);
+ try comptime testSqrt(f80);
+ try testSqrt(f128);
+ try comptime testSqrt(f128);
+ try testSqrt(c_longdouble);
+ try comptime testSqrt(c_longdouble);
+}
+
+fn testSqrt(comptime T: type) !void {
+ const eps = epsForType(T);
+ var four: T = 4.0;
+ try expect(@sqrt(four) == 2.0);
+ var nine: T = 9.0;
+ try expect(@sqrt(nine) == 3.0);
+ var twenty_five: T = 25.0;
+ try expect(@sqrt(twenty_five) == 5.0);
+ var sixty_four: T = 64.0;
+ try expect(@sqrt(sixty_four) == 8.0);
+ var one_point_one: T = 1.1;
+
+ try expect(math.approxEqAbs(T, @sqrt(one_point_one), 1.0488088481701516, eps));
+ var two: T = 2.0;
+ try expect(math.approxEqAbs(T, @sqrt(two), 1.4142135623730950, eps));
+ var three_point_six: T = 3.6;
+ try expect(math.approxEqAbs(T, @sqrt(three_point_six), 1.8973665961010276, eps));
+ var sixty_four_point_one: T = 64.1;
+ try expect(math.approxEqAbs(T, @sqrt(sixty_four_point_one), 8.00624756049923802, eps));
+ var twelve: T = 12.0;
+ try expect(math.approxEqAbs(T, @sqrt(twelve), 3.46410161513775459, eps));
+ var thirteen: T = 13.0;
+ try expect(math.approxEqAbs(T, @sqrt(thirteen), 3.60555127546398929, eps));
+ var fourteen: T = 14.0;
+ try expect(math.approxEqAbs(T, @sqrt(fourteen), 3.74165738677394139, eps));
+ var a: T = 7.539840;
+ try expect(math.approxEqAbs(T, @sqrt(a), 2.74587690911300684, eps));
+ var b: T = 19.230934;
+ try expect(math.approxEqAbs(T, @sqrt(b), 4.38530888307767894, eps));
+ var c: T = 8942.230469;
+ try expect(math.approxEqAbs(T, @sqrt(c), 94.5633674791671111, eps));
+
+ // special cases
+ var inf: T = math.inf(T);
+ try expect(math.isPositiveInf(@sqrt(inf)));
+ var zero: T = 0.0;
+ try expect(@sqrt(zero) == 0.0);
+ var neg_zero: T = -0.0;
+ try expect(@sqrt(neg_zero) == 0.0);
+ var neg_one: T = -1.0;
+ try expect(math.isNan(@sqrt(neg_one)));
+ var nan: T = math.nan(T);
+ try expect(math.isNan(@sqrt(nan)));
}
test "@sqrt with vectors" {
@@ -163,8 +336,8 @@ test "@sqrt with vectors" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- try comptime testSqrtWithVectors();
try testSqrtWithVectors();
+ try comptime testSqrtWithVectors();
}
fn testSqrtWithVectors() !void {
@@ -176,88 +349,64 @@ fn testSqrtWithVectors() !void {
try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
}
-test "more @sqrt f16 tests" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@sin f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- // TODO these are not all passing at comptime
- try expect(@sqrt(@as(f16, 0.0)) == 0.0);
- try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 2.0)), 1.414214, epsilon));
- try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 3.6)), 1.897367, epsilon));
- try expect(@sqrt(@as(f16, 4.0)) == 2.0);
- try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 7.539840)), 2.745877, epsilon));
- try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 19.230934)), 4.385309, epsilon));
- try expect(@sqrt(@as(f16, 64.0)) == 8.0);
- try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 64.1)), 8.006248, epsilon));
- try expect(math.approxEqAbs(f16, @sqrt(@as(f16, 8942.230469)), 94.563370, epsilon));
-
- // special cases
- try expect(math.isPositiveInf(@sqrt(@as(f16, math.inf(f16)))));
- try expect(@sqrt(@as(f16, 0.0)) == 0.0);
- try expect(@sqrt(@as(f16, -0.0)) == -0.0);
- try expect(math.isNan(@sqrt(@as(f16, -1.0))));
- try expect(math.isNan(@sqrt(@as(f16, math.nan(f16)))));
+ try testSin(f16);
+ try comptime testSin(f16);
}
-test "another, possibly redundant @sqrt test" {
+test "@sin f32/f64" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try testSqrtLegacy(f64, 12.0);
- try comptime testSqrtLegacy(f64, 12.0);
- try testSqrtLegacy(f32, 13.0);
- try comptime testSqrtLegacy(f32, 13.0);
- try testSqrtLegacy(f16, 13.0);
- try comptime testSqrtLegacy(f16, 13.0);
-
- // TODO: make this pass
- if (false) {
- const x = 14.0;
- const y = x * x;
- const z = @sqrt(y);
- try comptime expect(z == x);
- }
-}
-
-fn testSqrtLegacy(comptime T: type, x: T) !void {
- try expect(@sqrt(x * x) == x);
+ try testSin(f32);
+ comptime try testSin(f32);
+ try testSin(f64);
+ comptime try testSin(f64);
}
-test "@sin" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@sin f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testSin();
- try testSin();
+ try testSin(f80);
+ comptime try testSin(f80);
+ try testSin(f128);
+ comptime try testSin(f128);
+ try testSin(c_longdouble);
+ comptime try testSin(c_longdouble);
}
-fn testSin() !void {
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(@sin(@as(ty, 0)) == 0);
- try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
- try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2.0)), 1, eps));
- try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps));
- }
+fn testSin(comptime T: type) !void {
+ const eps = epsForType(T);
+ var zero: T = 0;
+ try expect(@sin(zero) == 0);
+ var pi: T = math.pi;
+ try expect(math.approxEqAbs(T, @sin(pi), 0, eps));
+ try expect(math.approxEqAbs(T, @sin(pi / 2.0), 1, eps));
+ try expect(math.approxEqAbs(T, @sin(pi / 4.0), 0.7071067811865475, eps));
}
test "@sin with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testSinWithVectors();
try testSinWithVectors();
+ try comptime testSinWithVectors();
}
fn testSinWithVectors() !void {
@@ -269,36 +418,64 @@ fn testSinWithVectors() !void {
try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
}
-test "@cos" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@cos f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testCos();
- try testCos();
+ try testCos(f16);
+ try comptime testCos(f16);
}
-fn testCos() !void {
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(@cos(@as(ty, 0)) == 1);
- try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
- try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2.0)), 0, eps));
- try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps));
- }
+test "@cos f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testCos(f32);
+ try comptime testCos(f32);
+ try testCos(f64);
+ try comptime testCos(f64);
+}
+
+test "@cos f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testCos(f80);
+ try comptime testCos(f80);
+ try testCos(f128);
+ try comptime testCos(f128);
+ try testCos(c_longdouble);
+ try comptime testCos(c_longdouble);
+}
+
+fn testCos(comptime T: type) !void {
+ const eps = epsForType(T);
+ var zero: T = 0;
+ try expect(@cos(zero) == 1);
+ var pi: T = math.pi;
+ try expect(math.approxEqAbs(T, @cos(pi), -1, eps));
+ try expect(math.approxEqAbs(T, @cos(pi / 2.0), 0, eps));
+ try expect(math.approxEqAbs(T, @cos(pi / 4.0), 0.7071067811865475, eps));
}
test "@cos with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testCosWithVectors();
try testCosWithVectors();
+ try comptime testCosWithVectors();
}
fn testCosWithVectors() !void {
@@ -310,35 +487,133 @@ fn testCosWithVectors() !void {
try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
}
-test "@exp" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@tan f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testExp();
- try testExp();
+ try testTan(f16);
+ try comptime testTan(f16);
}
-fn testExp() !void {
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(@exp(@as(ty, 0)) == 1);
- try expect(math.approxEqAbs(ty, @exp(@as(ty, 2)), 7.389056098930650, eps));
- try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps));
- }
+test "@tan f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testTan(f32);
+ try comptime testTan(f32);
+ try testTan(f64);
+ try comptime testTan(f64);
+}
+
+test "@tan f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testTan(f80);
+ try comptime testTan(f80);
+ try testTan(f128);
+ try comptime testTan(f128);
+ try testTan(c_longdouble);
+ try comptime testTan(c_longdouble);
+}
+
+fn testTan(comptime T: type) !void {
+ const eps = epsForType(T);
+ var zero: T = 0;
+ try expect(@tan(zero) == 0);
+ var pi: T = math.pi;
+ try expect(math.approxEqAbs(T, @tan(pi), 0, eps));
+ try expect(math.approxEqAbs(T, @tan(pi / 3.0), 1.732050807568878, eps));
+ try expect(math.approxEqAbs(T, @tan(pi / 4.0), 1, eps));
+}
+
+test "@tan with vectors" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testTanWithVectors();
+ try comptime testTanWithVectors();
+}
+
+fn testTanWithVectors() !void {
+ var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
+ var result = @tan(v);
+ try expect(math.approxEqAbs(f32, @tan(@as(f32, 1.1)), result[0], epsilon));
+ try expect(math.approxEqAbs(f32, @tan(@as(f32, 2.2)), result[1], epsilon));
+ try expect(math.approxEqAbs(f32, @tan(@as(f32, 3.3)), result[2], epsilon));
+ try expect(math.approxEqAbs(f32, @tan(@as(f32, 4.4)), result[3], epsilon));
+}
+
+test "@exp f16" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testExp(f16);
+ try comptime testExp(f16);
+}
+
+test "@exp f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testExp(f32);
+ try comptime testExp(f32);
+ try testExp(f64);
+ try comptime testExp(f64);
+}
+
+test "@exp f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testExp(f80);
+ try comptime testExp(f80);
+ try testExp(f128);
+ try comptime testExp(f128);
+ try testExp(c_longdouble);
+ try comptime testExp(c_longdouble);
+}
+
+fn testExp(comptime T: type) !void {
+ const eps = epsForType(T);
+ var zero: T = 0;
+ try expect(@exp(zero) == 1);
+ var two: T = 2;
+ try expect(math.approxEqAbs(T, @exp(two), 7.389056098930650, eps));
+ var five: T = 5;
+ try expect(math.approxEqAbs(T, @exp(five), 148.4131591025766, eps));
}
test "@exp with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testExpWithVectors();
try testExpWithVectors();
+ try comptime testExpWithVectors();
}
fn testExpWithVectors() !void {
@@ -350,35 +625,64 @@ fn testExpWithVectors() !void {
try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
}
-test "@exp2" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@exp2 f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testExp2();
- try testExp2();
+ try testExp2(f16);
+ try comptime testExp2(f16);
}
-fn testExp2() !void {
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(@exp2(@as(ty, 2)) == 4);
- try expect(math.approxEqAbs(ty, @exp2(@as(ty, 1.5)), 2.8284271247462, eps));
- try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps));
- }
+test "@exp2 f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testExp2(f32);
+ try comptime testExp2(f32);
+ try testExp2(f64);
+ try comptime testExp2(f64);
+}
+
+test "@exp2 f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testExp2(f80);
+ try comptime testExp2(f80);
+ try testExp2(f128);
+ try comptime testExp2(f128);
+ try testExp2(c_longdouble);
+ try comptime testExp2(c_longdouble);
+}
+
+fn testExp2(comptime T: type) !void {
+ const eps = epsForType(T);
+ var two: T = 2;
+ try expect(@exp2(two) == 4);
+ var one_point_five: T = 1.5;
+ try expect(math.approxEqAbs(T, @exp2(one_point_five), 2.8284271247462, eps));
+ var four_point_five: T = 4.5;
+ try expect(math.approxEqAbs(T, @exp2(four_point_five), 22.627416997969, eps));
}
test "@exp2 with @vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testExp2WithVectors();
try testExp2WithVectors();
+ try comptime testExp2WithVectors();
}
fn testExp2WithVectors() !void {
@@ -390,44 +694,62 @@ fn testExp2WithVectors() !void {
try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
}
-test "@log" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+test "@log f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testLog();
- try testLog();
+ try testLog(f16);
+ try comptime testLog(f16);
}
-fn testLog() !void {
- {
- var a: f16 = e;
- try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
- }
- {
- var a: f32 = e;
- try expect(@log(a) == 1 or @log(a) == @as(f32, @bitCast(@as(u32, 0x3f7fffff))));
- }
- {
- var a: f64 = e;
- try expect(@log(a) == 1 or @log(a) == @as(f64, @bitCast(@as(u64, 0x3ff0000000000000))));
- }
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(math.approxEqAbs(ty, @log(@as(ty, 2)), 0.6931471805599, eps));
- try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps));
- }
+test "@log f32/f64" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testLog(f32);
+ try comptime testLog(f32);
+ try testLog(f64);
+ try comptime testLog(f64);
+}
+
+test "@log f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testLog(f80);
+ try comptime testLog(f80);
+ try testLog(f128);
+ try comptime testLog(f128);
+ try testLog(c_longdouble);
+ try comptime testLog(c_longdouble);
+}
+
+fn testLog(comptime T: type) !void {
+ const eps = epsForType(T);
+ var e: T = math.e;
+ try expect(math.approxEqAbs(T, @log(e), 1, eps));
+ var two: T = 2;
+ try expect(math.approxEqAbs(T, @log(two), 0.6931471805599, eps));
+ var five: T = 5;
+ try expect(math.approxEqAbs(T, @log(five), 1.6094379124341, eps));
}
test "@log with @vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
{
var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
@@ -439,29 +761,57 @@ test "@log with @vectors" {
}
}
-test "@log2" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@log2 f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testLog2();
- try testLog2();
+ try testLog2(f16);
+ try comptime testLog2(f16);
}
-fn testLog2() !void {
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(@log2(@as(ty, 4)) == 2);
- try expect(math.approxEqAbs(ty, @log2(@as(ty, 6)), 2.5849625007212, eps));
- try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps));
- }
+test "@log2 f32/f64" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testLog2(f32);
+ try comptime testLog2(f32);
+ try testLog2(f64);
+ try comptime testLog2(f64);
+}
+
+test "@log2 f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testLog2(f80);
+ try comptime testLog2(f80);
+ try testLog2(f128);
+ try comptime testLog2(f128);
+ try testLog2(c_longdouble);
+ try comptime testLog2(c_longdouble);
+}
+
+fn testLog2(comptime T: type) !void {
+ const eps = epsForType(T);
+ var four: T = 4;
+ try expect(@log2(four) == 2);
+ var six: T = 6;
+ try expect(math.approxEqAbs(T, @log2(six), 2.5849625007212, eps));
+ var ten: T = 10;
+ try expect(math.approxEqAbs(T, @log2(ten), 3.3219280948874, eps));
}
test "@log2 with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
@@ -469,9 +819,10 @@ test "@log2 with vectors" {
if (builtin.zig_backend == .stage2_llvm and
builtin.cpu.arch == .aarch64 and
builtin.os.tag == .windows) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testLog2WithVectors();
try testLog2WithVectors();
+ try comptime testLog2WithVectors();
}
fn testLog2WithVectors() !void {
@@ -483,35 +834,64 @@ fn testLog2WithVectors() !void {
try expect(@log2(@as(f32, 0.4)) == result[3]);
}
-test "@log10" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
+test "@log10 f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testLog10();
- try testLog10();
+ try testLog10(f16);
+ try comptime testLog10(f16);
}
-fn testLog10() !void {
- inline for ([_]type{ f16, f32, f64 }) |ty| {
- const eps = epsForType(ty);
- try expect(@log10(@as(ty, 100)) == 2);
- try expect(math.approxEqAbs(ty, @log10(@as(ty, 15)), 1.176091259056, eps));
- try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps));
- }
+test "@log10 f32/f64" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testLog10(f32);
+ try comptime testLog10(f32);
+ try testLog10(f64);
+ try comptime testLog10(f64);
+}
+
+test "@log10 f80/f128/c_longdouble" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testLog10(f80);
+ try comptime testLog10(f80);
+ try testLog10(f128);
+ try comptime testLog10(f128);
+ try testLog10(c_longdouble);
+ try comptime testLog10(c_longdouble);
+}
+
+fn testLog10(comptime T: type) !void {
+ const eps = epsForType(T);
+ var hundred: T = 100;
+ try expect(@log10(hundred) == 2);
+ var fifteen: T = 15;
+ try expect(math.approxEqAbs(T, @log10(fifteen), 1.176091259056, eps));
+ var fifty: T = 50;
+ try expect(math.approxEqAbs(T, @log10(fifty), 1.698970004336, eps));
}
test "@log10 with vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testLog10WithVectors();
try testLog10WithVectors();
+ try comptime testLog10WithVectors();
}
fn testLog10WithVectors() !void {
@@ -523,41 +903,94 @@ fn testLog10WithVectors() !void {
try expect(@log10(@as(f32, 0.4)) == result[3]);
}
-test "@abs" {
+test "@abs f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try comptime testFabs();
- try testFabs();
+ try testFabs(f16);
+ try comptime testFabs(f16);
}
-fn testFabs() !void {
- try expect(@abs(@as(f16, -2.5)) == 2.5);
- try expect(@abs(@as(f16, 2.5)) == 2.5);
- try expect(@abs(@as(f32, -2.5)) == 2.5);
- try expect(@abs(@as(f32, 2.5)) == 2.5);
- try expect(@abs(@as(f64, -2.5)) == 2.5);
- try expect(@abs(@as(f64, 2.5)) == 2.5);
+test "@abs f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- // TODO test f128, and c_longdouble
- // https://github.com/ziglang/zig/issues/4026
- // {
- // var a: f80 = -2.5;
- // var b: f80 = 2.5;
- // try expect(@abs(a) == 2.5);
- // try expect(@abs(b) == 2.5);
- // }
+ try testFabs(f32);
+ try comptime testFabs(f32);
+ try testFabs(f64);
+ try comptime testFabs(f64);
}
-test "@abs with vectors" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+test "@abs f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testFabs(f80);
+ try comptime testFabs(f80);
+ try testFabs(f128);
+ try comptime testFabs(f128);
+ try testFabs(c_longdouble);
+ try comptime testFabs(c_longdouble);
+}
+
+fn testFabs(comptime T: type) !void {
+ var two_point_five: T = 2.5;
+ try expect(@abs(two_point_five) == 2.5);
+ var neg_two_point_five: T = -2.5;
+ try expect(@abs(neg_two_point_five) == 2.5);
+
+ var twelve: T = 12.0;
+ try expect(@abs(twelve) == 12.0);
+ var neg_fourteen: T = -14.0;
+ try expect(@abs(neg_fourteen) == 14.0);
+
+ // normals
+ var one: T = 1.0;
+ try expect(@abs(one) == 1.0);
+ var neg_one: T = -1.0;
+ try expect(@abs(neg_one) == 1.0);
+ var min: T = math.floatMin(T);
+ try expect(@abs(min) == math.floatMin(T));
+ var neg_min: T = -math.floatMin(T);
+ try expect(@abs(neg_min) == math.floatMin(T));
+ var max: T = math.floatMax(T);
+ try expect(@abs(max) == math.floatMax(T));
+ var neg_max: T = -math.floatMax(T);
+ try expect(@abs(neg_max) == math.floatMax(T));
+
+ // subnormals
+ var zero: T = 0.0;
+ try expect(@abs(zero) == 0.0);
+ var neg_zero: T = -0.0;
+ try expect(@abs(neg_zero) == 0.0);
+ var true_min: T = math.floatTrueMin(T);
+ try expect(@abs(true_min) == math.floatTrueMin(T));
+ var neg_true_min: T = -math.floatTrueMin(T);
+ try expect(@abs(neg_true_min) == math.floatTrueMin(T));
+
+ // non-finite numbers
+ var inf: T = math.inf(T);
+ try expect(math.isPositiveInf(@abs(inf)));
+ var neg_inf: T = -math.inf(T);
+ try expect(math.isPositiveInf(@abs(neg_inf)));
+ var nan: T = math.nan(T);
+ try expect(math.isNan(@abs(nan)));
+}
+
+test "@abs with vectors" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- try comptime testFabsWithVectors();
try testFabsWithVectors();
+ try comptime testFabsWithVectors();
}
fn testFabsWithVectors() !void {
@@ -569,109 +1002,77 @@ fn testFabsWithVectors() !void {
try expect(math.approxEqAbs(f32, @abs(@as(f32, -0.4)), result[3], epsilon));
}
-test "another, possibly redundant, @abs test" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@floor f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- try testFabsLegacy(f128, 12.0);
- try comptime testFabsLegacy(f128, 12.0);
- try testFabsLegacy(f64, 12.0);
- try comptime testFabsLegacy(f64, 12.0);
- try testFabsLegacy(f32, 12.0);
- try comptime testFabsLegacy(f32, 12.0);
- try testFabsLegacy(f16, 12.0);
- try comptime testFabsLegacy(f16, 12.0);
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- const x = 14.0;
- const y = -x;
- const z = @abs(y);
- try comptime std.testing.expectEqual(x, z);
+ try testFloor(f16);
+ try comptime testFloor(f16);
}
-test "@abs f80" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@floor f32/f64" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- try testFabsLegacy(f80, 12.0);
- try comptime testFabsLegacy(f80, 12.0);
-}
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
-fn testFabsLegacy(comptime T: type, x: T) !void {
- const y = -x;
- const z = @abs(y);
- try expect(x == z);
+ try testFloor(f32);
+ try comptime testFloor(f32);
+ try testFloor(f64);
+ try comptime testFloor(f64);
}
-test "a third @abs test, surely there should not be three fabs tests" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@floor f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
- // normals
- try expect(@abs(@as(T, 1.0)) == 1.0);
- try expect(@abs(@as(T, -1.0)) == 1.0);
- try expect(@abs(math.floatMin(T)) == math.floatMin(T));
- try expect(@abs(-math.floatMin(T)) == math.floatMin(T));
- try expect(@abs(math.floatMax(T)) == math.floatMax(T));
- try expect(@abs(-math.floatMax(T)) == math.floatMax(T));
-
- // subnormals
- try expect(@abs(@as(T, 0.0)) == 0.0);
- try expect(@abs(@as(T, -0.0)) == 0.0);
- try expect(@abs(math.floatTrueMin(T)) == math.floatTrueMin(T));
- try expect(@abs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
-
- // non-finite numbers
- try expect(math.isPositiveInf(@abs(math.inf(T))));
- try expect(math.isPositiveInf(@abs(-math.inf(T))));
- try expect(math.isNan(@abs(math.nan(T))));
- }
-}
-
-test "@floor" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testFloor();
- try testFloor();
-}
-
-fn testFloor() !void {
- try expect(@floor(@as(f16, 2.1)) == 2);
- try expect(@floor(@as(f32, 2.1)) == 2);
- try expect(@floor(@as(f64, 3.5)) == 3);
+ if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
+ // https://github.com/ziglang/zig/issues/12602
+ return error.SkipZigTest;
+ }
- // TODO test f128, and c_longdouble
- // https://github.com/ziglang/zig/issues/4026
- // {
- // var a: f80 = 3.5;
- // try expect(@floor(a) == 3);
- // }
+ try testFloor(f80);
+ try comptime testFloor(f80);
+ try testFloor(f128);
+ try comptime testFloor(f128);
+ try testFloor(c_longdouble);
+ try comptime testFloor(c_longdouble);
+}
+
+fn testFloor(comptime T: type) !void {
+ var two_point_one: T = 2.1;
+ try expect(@floor(two_point_one) == 2.0);
+ var neg_two_point_one: T = -2.1;
+ try expect(@floor(neg_two_point_one) == -3.0);
+ var three_point_five: T = 3.5;
+ try expect(@floor(three_point_five) == 3.0);
+ var neg_three_point_five: T = -3.5;
+ try expect(@floor(neg_three_point_five) == -4.0);
+ var twelve: T = 12.0;
+ try expect(@floor(twelve) == 12.0);
+ var neg_twelve: T = -12.0;
+ try expect(@floor(neg_twelve) == -12.0);
+ var fourteen_point_seven: T = 14.7;
+ try expect(@floor(fourteen_point_seven) == 14.0);
+ var neg_fourteen_point_seven: T = -14.7;
+ try expect(@floor(neg_fourteen_point_seven) == -15.0);
}
test "@floor with vectors" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and
+ !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
- try comptime testFloorWithVectors();
try testFloorWithVectors();
+ try comptime testFloorWithVectors();
}
fn testFloorWithVectors() !void {
@@ -683,90 +1084,77 @@ fn testFloorWithVectors() !void {
try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
}
-test "another, possibly redundant, @floor test" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@ceil f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- try testFloorLegacy(f64, 12.0);
- try comptime testFloorLegacy(f64, 12.0);
- try testFloorLegacy(f32, 12.0);
- try comptime testFloorLegacy(f32, 12.0);
- try testFloorLegacy(f16, 12.0);
- try comptime testFloorLegacy(f16, 12.0);
-
- const x = 14.0;
- const y = x + 0.7;
- const z = @floor(y);
- try comptime expect(x == z);
-}
-
-test "@floor f80" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
- // https://github.com/ziglang/zig/issues/12602
- return error.SkipZigTest;
- }
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try testFloorLegacy(f80, 12.0);
- try comptime testFloorLegacy(f80, 12.0);
+ try testCeil(f16);
+ try comptime testCeil(f16);
}
-test "@floor f128" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@ceil f32/f64" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- try testFloorLegacy(f128, 12.0);
- try comptime testFloorLegacy(f128, 12.0);
-}
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
-fn testFloorLegacy(comptime T: type, x: T) !void {
- const y = x + 0.6;
- const z = @floor(y);
- try expect(x == z);
+ try testCeil(f32);
+ try comptime testCeil(f32);
+ try testCeil(f64);
+ try comptime testCeil(f64);
}
-test "@ceil" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@ceil f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testCeil();
- try testCeil();
-}
-
-fn testCeil() !void {
- try expect(@ceil(@as(f16, 2.1)) == 3);
- try expect(@ceil(@as(f32, 2.1)) == 3);
- try expect(@ceil(@as(f64, 3.5)) == 4);
+ if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
+ // https://github.com/ziglang/zig/issues/12602
+ return error.SkipZigTest;
+ }
- // TODO test f128, and c_longdouble
- // https://github.com/ziglang/zig/issues/4026
- // {
- // var a: f80 = 3.5;
- // try expect(@ceil(a) == 4);
- // }
+ try testCeil(f80);
+ try comptime testCeil(f80);
+ try testCeil(f128);
+ try comptime testCeil(f128);
+ try testCeil(c_longdouble);
+ try comptime testCeil(c_longdouble);
+}
+
+fn testCeil(comptime T: type) !void {
+ var two_point_one: T = 2.1;
+ try expect(@ceil(two_point_one) == 3.0);
+ var neg_two_point_one: T = -2.1;
+ try expect(@ceil(neg_two_point_one) == -2.0);
+ var three_point_five: T = 3.5;
+ try expect(@ceil(three_point_five) == 4.0);
+ var neg_three_point_five: T = -3.5;
+ try expect(@ceil(neg_three_point_five) == -3.0);
+ var twelve: T = 12.0;
+ try expect(@ceil(twelve) == 12.0);
+ var neg_twelve: T = -12.0;
+ try expect(@ceil(neg_twelve) == -12.0);
+ var fourteen_point_seven: T = 14.7;
+ try expect(@ceil(fourteen_point_seven) == 15.0);
+ var neg_fourteen_point_seven: T = -14.7;
+ try expect(@ceil(neg_fourteen_point_seven) == -14.0);
}
test "@ceil with vectors" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and
+ !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
- try comptime testCeilWithVectors();
try testCeilWithVectors();
+ try comptime testCeilWithVectors();
}
fn testCeilWithVectors() !void {
@@ -778,90 +1166,87 @@ fn testCeilWithVectors() !void {
try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
}
-test "another, possibly redundant, @ceil test" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@trunc f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- try testCeilLegacy(f64, 12.0);
- try comptime testCeilLegacy(f64, 12.0);
- try testCeilLegacy(f32, 12.0);
- try comptime testCeilLegacy(f32, 12.0);
- try testCeilLegacy(f16, 12.0);
- try comptime testCeilLegacy(f16, 12.0);
-
- const x = 14.0;
- const y = x - 0.7;
- const z = @ceil(y);
- try comptime expect(x == z);
-}
-
-test "@ceil f80" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
- // https://github.com/ziglang/zig/issues/12602
+ if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
+ // https://github.com/ziglang/zig/issues/16846
return error.SkipZigTest;
}
- try testCeilLegacy(f80, 12.0);
- try comptime testCeilLegacy(f80, 12.0);
+ try testTrunc(f16);
+ try comptime testTrunc(f16);
}
-test "@ceil f128" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@trunc f32/f64" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
- try testCeilLegacy(f128, 12.0);
- try comptime testCeilLegacy(f128, 12.0);
-}
+ if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
+ // https://github.com/ziglang/zig/issues/16846
+ return error.SkipZigTest;
+ }
-fn testCeilLegacy(comptime T: type, x: T) !void {
- const y = x - 0.8;
- const z = @ceil(y);
- try expect(x == z);
+ try testTrunc(f32);
+ try comptime testTrunc(f32);
+ try testTrunc(f64);
+ try comptime testTrunc(f64);
}
-test "@trunc" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "@trunc f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
- try comptime testTrunc();
- try testTrunc();
-}
-
-fn testTrunc() !void {
- try expect(@trunc(@as(f16, 2.1)) == 2);
- try expect(@trunc(@as(f32, 2.1)) == 2);
- try expect(@trunc(@as(f64, -3.5)) == -3);
+ if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
+ // https://github.com/ziglang/zig/issues/12602
+ return error.SkipZigTest;
+ }
- // TODO test f128, and c_longdouble
- // https://github.com/ziglang/zig/issues/4026
- // {
- // var a: f80 = -3.5;
- // try expect(@trunc(a) == -3);
- // }
+ try testTrunc(f80);
+ try comptime testTrunc(f80);
+ try testTrunc(f128);
+ try comptime testTrunc(f128);
+ try testTrunc(c_longdouble);
+ try comptime testTrunc(c_longdouble);
+}
+
+fn testTrunc(comptime T: type) !void {
+ var two_point_one: T = 2.1;
+ try expect(@trunc(two_point_one) == 2.0);
+ var neg_two_point_one: T = -2.1;
+ try expect(@trunc(neg_two_point_one) == -2.0);
+ var three_point_five: T = 3.5;
+ try expect(@trunc(three_point_five) == 3.0);
+ var neg_three_point_five: T = -3.5;
+ try expect(@trunc(neg_three_point_five) == -3.0);
+ var twelve: T = 12.0;
+ try expect(@trunc(twelve) == 12.0);
+ var neg_twelve: T = -12.0;
+ try expect(@trunc(neg_twelve) == -12.0);
+ var fourteen_point_seven: T = 14.7;
+ try expect(@trunc(fourteen_point_seven) == 14.0);
+ var neg_fourteen_point_seven: T = -14.7;
+ try expect(@trunc(neg_fourteen_point_seven) == -14.0);
}
test "@trunc with vectors" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64 and
+ !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
- try comptime testTruncWithVectors();
try testTruncWithVectors();
+ try comptime testTruncWithVectors();
}
fn testTruncWithVectors() !void {
@@ -873,183 +1258,98 @@ fn testTruncWithVectors() !void {
try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
}
-test "another, possibly redundant, @trunc test" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "neg f16" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
- // https://github.com/ziglang/zig/issues/16846
- return error.SkipZigTest;
- }
-
- try testTruncLegacy(f64, 12.0);
- try comptime testTruncLegacy(f64, 12.0);
- try testTruncLegacy(f32, 12.0);
- try comptime testTruncLegacy(f32, 12.0);
- try testTruncLegacy(f16, 12.0);
- try comptime testTruncLegacy(f16, 12.0);
-
- const x = 14.0;
- const y = x + 0.7;
- const z = @trunc(y);
- try comptime expect(x == z);
-}
-
-test "@trunc f80" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
- // https://github.com/ziglang/zig/issues/12602
- return error.SkipZigTest;
- }
-
- try testTruncLegacy(f80, 12.0);
- try comptime testTruncLegacy(f80, 12.0);
- comptime {
- const x: f80 = 12.0;
- const y = x + 0.8;
- const z = @trunc(y);
- try expect(x == z);
- }
-}
-
-test "@trunc f128" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
- try testTruncLegacy(f128, 12.0);
- try comptime testTruncLegacy(f128, 12.0);
-}
-
-fn testTruncLegacy(comptime T: type, x: T) !void {
- {
- const y = x + 0.8;
- const z = @trunc(y);
- try expect(x == z);
- }
-
- {
- const y = -x - 0.8;
- const z = @trunc(y);
- try expect(-x == z);
- }
-}
-
-test "negation f16" {
- if (no_x86_64_hardware_f16_support) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
if (builtin.os.tag == .freebsd) {
// TODO file issue to track this failure
return error.SkipZigTest;
}
- const S = struct {
- fn doTheTest() !void {
- var a: f16 = 1;
- a = -a;
- try expect(a == -1);
- a = -a;
- try expect(a == 1);
- }
- };
-
- try S.doTheTest();
- try comptime S.doTheTest();
+ try testNeg(f16);
+ try comptime testNeg(f16);
}
-test "negation f32" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "neg f32/f64" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const S = struct {
- fn doTheTest() !void {
- var a: f32 = 1;
- a = -a;
- try expect(a == -1);
- a = -a;
- try expect(a == 1);
- }
- };
-
- try S.doTheTest();
- try comptime S.doTheTest();
-}
-
-test "negation f64" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
- const S = struct {
- fn doTheTest() !void {
- var a: f64 = 1;
- a = -a;
- try expect(a == -1);
- a = -a;
- try expect(a == 1);
- }
- };
-
- try S.doTheTest();
- try comptime S.doTheTest();
+ try testNeg(f32);
+ try comptime testNeg(f32);
+ try testNeg(f64);
+ try comptime testNeg(f64);
}
-test "negation f80" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+test "neg f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const S = struct {
- fn doTheTest() !void {
- var a: f80 = 1;
- a = -a;
- try expect(a == -1);
- a = -a;
- try expect(a == 1);
- }
- };
-
- try S.doTheTest();
- try comptime S.doTheTest();
-}
-
-test "negation f128" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const S = struct {
- fn doTheTest() !void {
- var a: f128 = 1;
- a = -a;
- try expect(a == -1);
- a = -a;
- try expect(a == 1);
- }
- };
-
- try S.doTheTest();
- try comptime S.doTheTest();
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+ try testNeg(f80);
+ try comptime testNeg(f80);
+ try testNeg(f128);
+ try comptime testNeg(f128);
+ try testNeg(c_longdouble);
+ try comptime testNeg(c_longdouble);
+}
+
+fn testNeg(comptime T: type) !void {
+ var two_point_five: T = 2.5;
+ try expect(-two_point_five == -2.5);
+ var neg_two_point_five: T = -2.5;
+ try expect(-neg_two_point_five == 2.5);
+
+ var twelve: T = 12.0;
+ try expect(-twelve == -12.0);
+ var neg_fourteen: T = -14.0;
+ try expect(-neg_fourteen == 14.0);
+
+ // normals
+ var one: T = 1.0;
+ try expect(-one == -1.0);
+ var neg_one: T = -1.0;
+ try expect(-neg_one == 1.0);
+ var min: T = math.floatMin(T);
+ try expect(-min == -math.floatMin(T));
+ var neg_min: T = -math.floatMin(T);
+ try expect(-neg_min == math.floatMin(T));
+ var max: T = math.floatMax(T);
+ try expect(-max == -math.floatMax(T));
+ var neg_max: T = -math.floatMax(T);
+ try expect(-neg_max == math.floatMax(T));
+
+ // subnormals
+ var zero: T = 0.0;
+ try expect(-zero == -0.0);
+ var neg_zero: T = -0.0;
+ try expect(-neg_zero == 0.0);
+ var true_min: T = math.floatTrueMin(T);
+ try expect(-true_min == -math.floatTrueMin(T));
+ var neg_true_min: T = -math.floatTrueMin(T);
+ try expect(-neg_true_min == math.floatTrueMin(T));
+
+ // non-finite numbers
+ var inf: T = math.inf(T);
+ try expect(math.isNegativeInf(-inf));
+ var neg_inf: T = -math.inf(T);
+ try expect(math.isPositiveInf(-neg_inf));
+ var nan: T = math.nan(T);
+ try expect(math.isNan(-nan));
+ try expect(math.signbit(-nan));
+ var neg_nan: T = -math.nan(T);
+ try expect(math.isNan(-neg_nan));
+ try expect(!math.signbit(-neg_nan));
}
test "eval @setFloatMode at compile-time" {
@@ -1075,11 +1375,11 @@ test "f128 at compile time is lossy" {
}
test "comptime fixed-width float zero divided by zero produces NaN" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
inline for (.{ f16, f32, f64, f80, f128 }) |F| {
try expect(math.isNan(@as(F, 0) / @as(F, 0)));
@@ -1104,99 +1404,3 @@ test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
test "comptime_float zero divided by zero produces zero" {
try expect((0.0 / 0.0) == 0.0);
}
-
-test "nan negation f16" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const nan_comptime = comptime math.nan(f16);
- const neg_nan_comptime = -nan_comptime;
-
- var nan_runtime = math.nan(f16);
- const neg_nan_runtime = -nan_runtime;
-
- try expect(!math.signbit(nan_runtime));
- try expect(math.signbit(neg_nan_runtime));
-
- try expect(!math.signbit(nan_comptime));
- try expect(math.signbit(neg_nan_comptime));
-}
-
-test "nan negation f32" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const nan_comptime = comptime math.nan(f32);
- const neg_nan_comptime = -nan_comptime;
-
- var nan_runtime = math.nan(f32);
- const neg_nan_runtime = -nan_runtime;
-
- try expect(!math.signbit(nan_runtime));
- try expect(math.signbit(neg_nan_runtime));
-
- try expect(!math.signbit(nan_comptime));
- try expect(math.signbit(neg_nan_comptime));
-}
-
-test "nan negation f64" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const nan_comptime = comptime math.nan(f64);
- const neg_nan_comptime = -nan_comptime;
-
- var nan_runtime = math.nan(f64);
- const neg_nan_runtime = -nan_runtime;
-
- try expect(!math.signbit(nan_runtime));
- try expect(math.signbit(neg_nan_runtime));
-
- try expect(!math.signbit(nan_comptime));
- try expect(math.signbit(neg_nan_comptime));
-}
-
-test "nan negation f128" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const nan_comptime = comptime math.nan(f128);
- const neg_nan_comptime = -nan_comptime;
-
- var nan_runtime = math.nan(f128);
- const neg_nan_runtime = -nan_runtime;
-
- try expect(!math.signbit(nan_runtime));
- try expect(math.signbit(neg_nan_runtime));
-
- try expect(!math.signbit(nan_comptime));
- try expect(math.signbit(neg_nan_comptime));
-}
-
-test "nan negation f80" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
- const nan_comptime = comptime math.nan(f80);
- const neg_nan_comptime = -nan_comptime;
-
- var nan_runtime = math.nan(f80);
- const neg_nan_runtime = -nan_runtime;
-
- try expect(!math.signbit(nan_runtime));
- try expect(math.signbit(neg_nan_runtime));
-
- try expect(!math.signbit(nan_comptime));
- try expect(math.signbit(neg_nan_comptime));
-}
diff --git a/test/behavior/math.zig b/test/behavior/math.zig
@@ -410,12 +410,11 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {
test "division" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
// https://github.com/ziglang/zig/issues/16846
@@ -1437,19 +1436,28 @@ fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
try expect(@abs(@mod(@as(T, a), @as(T, b)) - @as(T, c)) < epsilon);
}
-test "@round" {
+test "@round f16" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
+
+ try testRound(f16, 12.0);
+ try comptime testRound(f16, 12.0);
+}
+
+test "@round f32/f64" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
try testRound(f64, 12.0);
try comptime testRound(f64, 12.0);
try testRound(f32, 12.0);
try comptime testRound(f32, 12.0);
- try testRound(f16, 12.0);
- try comptime testRound(f16, 12.0);
const x = 14.0;
const y = x + 0.4;
@@ -1464,6 +1472,7 @@ test "@round f80" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
try testRound(f80, 12.0);
try comptime testRound(f80, 12.0);
@@ -1476,6 +1485,7 @@ test "@round f128" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
try testRound(f128, 12.0);
try comptime testRound(f128, 12.0);
@@ -1608,11 +1618,6 @@ test "signed zeros are represented properly" {
try comptime S.doTheTest();
}
-test "comptime sin and ln" {
- const v = comptime (@sin(@as(f32, 1)) + @log(@as(f32, 5)));
- try expect(v == @sin(@as(f32, 1)) + @log(@as(f32, 5)));
-}
-
test "absFloat" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig
@@ -10,6 +10,7 @@ test "@max" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
@@ -25,12 +26,11 @@ test "@max" {
test "@max on vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
@@ -74,12 +74,11 @@ test "@min" {
test "@min for vectors" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
@@ -104,12 +103,12 @@ test "@min for vectors" {
}
test "@min/max for floats" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn doTheTest(comptime T: type) !void {
@@ -179,11 +178,11 @@ test "@min/@max notices bounds" {
test "@min/@max notices vector bounds" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var x: @Vector(2, u16) = .{ 140, 40 };
const y: @Vector(2, u64) = .{ 5, 100 };
@@ -232,11 +231,11 @@ test "@min/@max notices bounds from types" {
test "@min/@max notices bounds from vector types" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var x: @Vector(2, u16) = .{ 30, 67 };
var y: @Vector(2, u32) = .{ 20, 500 };
@@ -272,11 +271,11 @@ test "@min/@max notices bounds from types when comptime-known value is undef" {
test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var x: @Vector(2, u32) = .{ 1_000_000, 12345 };
const y: @Vector(2, u16) = .{ 10, undefined };
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
@@ -1651,7 +1651,6 @@ test "instantiate struct with comptime field" {
test "struct field pointer has correct alignment" {
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; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1684,7 +1683,6 @@ test "struct field pointer has correct alignment" {
test "extern struct field pointer has correct alignment" {
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; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
@@ -1534,7 +1534,6 @@ test "coerce enum literal to union in result loc" {
test "defined-layout union field pointer has correct alignment" {
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; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1572,7 +1571,6 @@ test "defined-layout union field pointer has correct alignment" {
test "undefined-layout union field pointer has correct alignment" {
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; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1610,7 +1608,6 @@ test "undefined-layout union field pointer has correct alignment" {
test "packed union field pointer has correct alignment" {
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; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig
@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;
test "implicit cast vector to array - bool" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -27,12 +26,12 @@ test "implicit cast vector to array - bool" {
test "vector wrap operators" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and
+ !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest() !void {
@@ -214,13 +213,12 @@ test "array vector coercion - odd sizes" {
}
test "array to vector with element type coercion" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64 and
- !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .f16c)) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {
@@ -236,7 +234,6 @@ test "array to vector with element type coercion" {
test "peer type resolution with coercible element types" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1440,7 +1437,6 @@ test "vector pointer is indexable" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
@@ -1466,7 +1462,6 @@ test "boolean vector with 2 or more booleans" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
// TODO: try removing this after <https://github.com/ziglang/zig/issues/13782>:
@@ -1483,7 +1478,6 @@ test "bitcast to vector with different child type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO