mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 06:15:21 +00:00
Sema: improve lowering of stores to bitcasted vector pointers
Detect if we are storing an array operand to a bitcasted vector pointer. If so, we instead reach through the bitcasted pointer to the vector pointer, bitcast the array operand to a vector, and then lower this as a store of a vector value to a vector pointer. This generally results in better code, as well as working around an LLVM bug. See #11154
This commit is contained in:
parent
eee989d2a0
commit
b2a1b4c085
52
src/Sema.zig
52
src/Sema.zig
@ -13276,7 +13276,7 @@ fn checkFloatType(
|
||||
ty: Type,
|
||||
) CompileError!void {
|
||||
switch (ty.zigTypeTag()) {
|
||||
.ComptimeFloat, .Float => {},
|
||||
.ComptimeInt, .ComptimeFloat, .Float => {},
|
||||
else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty}),
|
||||
}
|
||||
}
|
||||
@ -17177,10 +17177,25 @@ fn storePtr2(
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO do the same thing for anon structs as for tuples above.
|
||||
|
||||
// Detect if we are storing an array operand to a bitcasted vector pointer.
|
||||
// If so, we instead reach through the bitcasted pointer to the vector pointer,
|
||||
// bitcast the array operand to a vector, and then lower this as a store of
|
||||
// a vector value to a vector pointer. This generally results in better code,
|
||||
// as well as working around an LLVM bug:
|
||||
// https://github.com/ziglang/zig/issues/11154
|
||||
if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| {
|
||||
const vector_ty = sema.typeOf(vector_ptr).childType();
|
||||
const vector = try sema.coerce(block, vector_ty, uncasted_operand, operand_src);
|
||||
try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store);
|
||||
return;
|
||||
}
|
||||
|
||||
const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src);
|
||||
const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
|
||||
|
||||
const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
|
||||
const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
|
||||
const operand_val = maybe_operand_val orelse {
|
||||
try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
|
||||
break :rs operand_src;
|
||||
@ -17203,6 +17218,39 @@ fn storePtr2(
|
||||
_ = try block.addBinOp(air_tag, ptr, operand);
|
||||
}
|
||||
|
||||
/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
|
||||
/// pointer. Only if the final element type matches the vector element type, and the
|
||||
/// lengths match.
|
||||
fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref {
|
||||
const array_ty = sema.typeOf(ptr).childType();
|
||||
if (array_ty.zigTypeTag() != .Array) return null;
|
||||
var ptr_inst = Air.refToIndex(ptr) orelse return null;
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
const air_tags = sema.air_instructions.items(.tag);
|
||||
const prev_ptr = while (air_tags[ptr_inst] == .bitcast) {
|
||||
const prev_ptr = air_datas[ptr_inst].ty_op.operand;
|
||||
const prev_ptr_ty = sema.typeOf(prev_ptr);
|
||||
const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) {
|
||||
.single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data,
|
||||
.pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type,
|
||||
else => return null,
|
||||
};
|
||||
if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr;
|
||||
ptr_inst = Air.refToIndex(prev_ptr) orelse return null;
|
||||
} else return null;
|
||||
|
||||
// We have a pointer-to-array and a pointer-to-vector. If the elements and
|
||||
// lengths match, return the result.
|
||||
const vector_ty = sema.typeOf(prev_ptr).childType();
|
||||
if (array_ty.childType().eql(vector_ty.childType()) and
|
||||
array_ty.arrayLen() == vector_ty.vectorLen())
|
||||
{
|
||||
return prev_ptr;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Call when you have Value objects rather than Air instructions, and you want to
|
||||
/// assert the store must be done at comptime.
|
||||
fn storePtrVal(
|
||||
|
||||
@ -3931,15 +3931,12 @@ pub const Value = extern union {
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt fabs for f80");
|
||||
@panic("TODO implement compiler_rt fabs for f80 (__fabsx)");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @fabs(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt fabs for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @fabs(f));
|
||||
},
|
||||
@ -3963,15 +3960,12 @@ pub const Value = extern union {
|
||||
},
|
||||
80 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt floor for f80");
|
||||
@panic("TODO implement compiler_rt floor for f80 (__floorx)");
|
||||
}
|
||||
const f = val.toFloat(f80);
|
||||
return Value.Tag.float_80.create(arena, @floor(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt floor for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @floor(f));
|
||||
},
|
||||
@ -4001,9 +3995,6 @@ pub const Value = extern union {
|
||||
return Value.Tag.float_80.create(arena, @ceil(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt ceil for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @ceil(f));
|
||||
},
|
||||
@ -4033,9 +4024,6 @@ pub const Value = extern union {
|
||||
return Value.Tag.float_80.create(arena, @round(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt round for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @round(f));
|
||||
},
|
||||
@ -4065,9 +4053,6 @@ pub const Value = extern union {
|
||||
return Value.Tag.float_80.create(arena, @trunc(f));
|
||||
},
|
||||
128 => {
|
||||
if (true) {
|
||||
@panic("TODO implement compiler_rt trunc for f128");
|
||||
}
|
||||
const f = val.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, @trunc(f));
|
||||
},
|
||||
|
||||
@ -95,8 +95,29 @@ test "comptime_int @intToFloat" {
|
||||
}
|
||||
}
|
||||
|
||||
test "@intToFloat" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
try testIntToFloat(-2);
|
||||
}
|
||||
|
||||
fn testIntToFloat(k: i32) !void {
|
||||
const f = @intToFloat(f32, k);
|
||||
const i = @floatToInt(i32, f);
|
||||
try expect(i == k);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "@floatToInt" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
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_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
@ -1007,8 +1028,6 @@ test "peer type resolve array pointer and unknown pointer" {
|
||||
}
|
||||
|
||||
test "comptime float casts" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
const a = @intToFloat(comptime_float, 1);
|
||||
try expect(a == 1);
|
||||
try expect(@TypeOf(a) == comptime_float);
|
||||
|
||||
@ -333,7 +333,6 @@ fn testLog() !void {
|
||||
}
|
||||
|
||||
test "@log with vectors" {
|
||||
if (builtin.zig_backend == .stage2_llvm) 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_aarch64) return error.SkipZigTest; // TODO
|
||||
@ -343,15 +342,19 @@ test "@log with vectors" {
|
||||
{
|
||||
var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log(v);
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(@log(@as(f32, 1.1)) == result[0]);
|
||||
try expect(@log(@as(f32, 2.2)) == result[1]);
|
||||
try expect(@log(@as(f32, 0.3)) == result[2]);
|
||||
try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
|
||||
try expect(@log(@as(f32, 0.4)) == result[3]);
|
||||
}
|
||||
}
|
||||
|
||||
test "@log2" {
|
||||
if (builtin.zig_backend != .stage1) 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_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
|
||||
|
||||
comptime try testLog2();
|
||||
try testLog2();
|
||||
@ -368,15 +371,19 @@ fn testLog2() !void {
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log2(v);
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
|
||||
try expect(@log2(@as(f32, 1.1)) == result[0]);
|
||||
try expect(@log2(@as(f32, 2.2)) == result[1]);
|
||||
try expect(@log2(@as(f32, 0.3)) == result[2]);
|
||||
try expect(@log2(@as(f32, 0.4)) == result[3]);
|
||||
}
|
||||
}
|
||||
|
||||
test "@log10" {
|
||||
if (builtin.zig_backend != .stage1) 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_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
|
||||
|
||||
comptime try testLog10();
|
||||
try testLog10();
|
||||
@ -393,10 +400,10 @@ fn testLog10() !void {
|
||||
{
|
||||
var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
|
||||
var result = @log10(v);
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
|
||||
try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
|
||||
try expect(@log10(@as(f32, 1.1)) == result[0]);
|
||||
try expect(@log10(@as(f32, 2.2)) == result[1]);
|
||||
try expect(@log10(@as(f32, 0.3)) == result[2]);
|
||||
try expect(@log10(@as(f32, 0.4)) == result[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,7 +544,71 @@ fn testTrunc() !void {
|
||||
}
|
||||
}
|
||||
|
||||
test "negation" {
|
||||
test "negation f16" {
|
||||
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_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
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();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "negation f32" {
|
||||
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_c) return error.SkipZigTest; // TODO
|
||||
|
||||
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();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "negation f64" {
|
||||
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
|
||||
|
||||
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();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "negation f80" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.os.tag == .freebsd) {
|
||||
@ -547,11 +618,37 @@ test "negation" {
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
|
||||
var a: T = 1;
|
||||
a = -a;
|
||||
try expect(a == -1);
|
||||
}
|
||||
var a: f80 = 1;
|
||||
a = -a;
|
||||
try expect(a == -1);
|
||||
a = -a;
|
||||
try expect(a == 1);
|
||||
}
|
||||
};
|
||||
|
||||
try S.doTheTest();
|
||||
comptime try 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_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.os.tag == .freebsd) {
|
||||
// TODO file issue to track this failure
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -583,7 +680,13 @@ test "float literal at compile time not lossy" {
|
||||
}
|
||||
|
||||
test "f128 at compile time is lossy" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend != .stage1) {
|
||||
// this one is happening because we represent comptime-known f128 integers with
|
||||
// Value.Tag.bigint and only convert to f128 representation if it stops being an
|
||||
// integer. Is this something we want? need to have a lang spec discussion on this
|
||||
// topic.
|
||||
return error.SkipZigTest; // TODO
|
||||
}
|
||||
|
||||
try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ const expectEqualSlices = std.testing.expectEqualSlices;
|
||||
const maxInt = std.math.maxInt;
|
||||
const minInt = std.math.minInt;
|
||||
const mem = std.mem;
|
||||
const has_f80_rt = builtin.cpu.arch == .x86_64;
|
||||
|
||||
test "assignment operators" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
@ -1046,12 +1045,14 @@ fn testSqrt(comptime T: type, x: T) !void {
|
||||
}
|
||||
|
||||
test "@fabs" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
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_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
|
||||
try testFabs(f128, 12.0);
|
||||
comptime try testFabs(f128, 12.0);
|
||||
if (has_f80_rt) try testFabs(f80, 12.0);
|
||||
// comptime try testFabs(f80, 12.0);
|
||||
try testFabs(f64, 12.0);
|
||||
comptime try testFabs(f64, 12.0);
|
||||
try testFabs(f32, 12.0);
|
||||
@ -1065,20 +1066,25 @@ test "@fabs" {
|
||||
comptime try expectEqual(x, z);
|
||||
}
|
||||
|
||||
test "@fabs f80" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testFabs(f80, 12.0);
|
||||
comptime try testFabs(f80, 12.0);
|
||||
}
|
||||
|
||||
fn testFabs(comptime T: type, x: T) !void {
|
||||
const y = -x;
|
||||
const z = @fabs(y);
|
||||
try expectEqual(x, z);
|
||||
try expect(x == z);
|
||||
}
|
||||
|
||||
test "@floor" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
// FIXME: Generates a floorl function call
|
||||
// testFloor(f128, 12.0);
|
||||
comptime try testFloor(f128, 12.0);
|
||||
// try testFloor(f80, 12.0);
|
||||
comptime try testFloor(f80, 12.0);
|
||||
try testFloor(f64, 12.0);
|
||||
comptime try testFloor(f64, 12.0);
|
||||
try testFloor(f32, 12.0);
|
||||
@ -1089,23 +1095,39 @@ test "@floor" {
|
||||
const x = 14.0;
|
||||
const y = x + 0.7;
|
||||
const z = @floor(y);
|
||||
comptime try expectEqual(x, z);
|
||||
comptime try expect(x == z);
|
||||
}
|
||||
|
||||
test "@floor f80" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
try testFloor(f80, 12.0);
|
||||
comptime try testFloor(f80, 12.0);
|
||||
}
|
||||
|
||||
test "@floor f128" {
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
// Fails because it incorrectly lowers to a floorl function call.
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
testFloor(f128, 12.0);
|
||||
comptime try testFloor(f128, 12.0);
|
||||
}
|
||||
|
||||
fn testFloor(comptime T: type, x: T) !void {
|
||||
const y = x + 0.6;
|
||||
const z = @floor(y);
|
||||
try expectEqual(x, z);
|
||||
try expect(x == z);
|
||||
}
|
||||
|
||||
test "@ceil" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
// FIXME: Generates a ceill function call
|
||||
//testCeil(f128, 12.0);
|
||||
comptime try testCeil(f128, 12.0);
|
||||
// try testCeil(f80, 12.0);
|
||||
comptime try testCeil(f80, 12.0);
|
||||
try testCeil(f64, 12.0);
|
||||
comptime try testCeil(f64, 12.0);
|
||||
try testCeil(f32, 12.0);
|
||||
@ -1116,29 +1138,40 @@ test "@ceil" {
|
||||
const x = 14.0;
|
||||
const y = x - 0.7;
|
||||
const z = @ceil(y);
|
||||
comptime try expectEqual(x, z);
|
||||
comptime try expect(x == z);
|
||||
}
|
||||
|
||||
test "@ceil f80" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testCeil(f80, 12.0);
|
||||
comptime try testCeil(f80, 12.0);
|
||||
}
|
||||
|
||||
test "@ceil f128" {
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
// Fails because it incorrectly lowers to a ceill function call.
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
testCeil(f128, 12.0);
|
||||
comptime try testCeil(f128, 12.0);
|
||||
}
|
||||
|
||||
fn testCeil(comptime T: type, x: T) !void {
|
||||
const y = x - 0.8;
|
||||
const z = @ceil(y);
|
||||
try expectEqual(x, z);
|
||||
try expect(x == z);
|
||||
}
|
||||
|
||||
test "@trunc" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
// FIXME: Generates a truncl function call
|
||||
//testTrunc(f128, 12.0);
|
||||
comptime try testTrunc(f128, 12.0);
|
||||
// try testTrunc(f80, 12.0);
|
||||
// comptime try testTrunc(f80, 12.0);
|
||||
comptime {
|
||||
const x: f80 = 12.0;
|
||||
const y = x + 0.8;
|
||||
const z = @trunc(y);
|
||||
try expectEqual(x, z);
|
||||
}
|
||||
try testTrunc(f64, 12.0);
|
||||
comptime try testTrunc(f64, 12.0);
|
||||
try testTrunc(f32, 12.0);
|
||||
@ -1149,31 +1182,54 @@ test "@trunc" {
|
||||
const x = 14.0;
|
||||
const y = x + 0.7;
|
||||
const z = @trunc(y);
|
||||
comptime try expectEqual(x, z);
|
||||
comptime try expect(x == z);
|
||||
}
|
||||
|
||||
test "@trunc f80" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testTrunc(f80, 12.0);
|
||||
comptime try testTrunc(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 == .stage1) {
|
||||
// Fails because it incorrectly lowers to a truncl function call.
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
testTrunc(f128, 12.0);
|
||||
comptime try testTrunc(f128, 12.0);
|
||||
}
|
||||
|
||||
fn testTrunc(comptime T: type, x: T) !void {
|
||||
{
|
||||
const y = x + 0.8;
|
||||
const z = @trunc(y);
|
||||
try expectEqual(x, z);
|
||||
try expect(x == z);
|
||||
}
|
||||
|
||||
{
|
||||
const y = -x - 0.8;
|
||||
const z = @trunc(y);
|
||||
try expectEqual(-x, z);
|
||||
try expect(-x == z);
|
||||
}
|
||||
}
|
||||
|
||||
test "@round" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
// FIXME: Generates a roundl function call
|
||||
//testRound(f128, 12.0);
|
||||
comptime try testRound(f128, 12.0);
|
||||
// try testRound(f80, 12.0);
|
||||
comptime try testRound(f80, 12.0);
|
||||
try testRound(f64, 12.0);
|
||||
comptime try testRound(f64, 12.0);
|
||||
try testRound(f32, 12.0);
|
||||
@ -1184,13 +1240,35 @@ test "@round" {
|
||||
const x = 14.0;
|
||||
const y = x + 0.4;
|
||||
const z = @round(y);
|
||||
comptime try expectEqual(x, z);
|
||||
comptime try expect(x == z);
|
||||
}
|
||||
|
||||
test "@round f80" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testRound(f80, 12.0);
|
||||
comptime try testRound(f80, 12.0);
|
||||
}
|
||||
|
||||
test "@round f128" {
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
// Fails because it incorrectly lowers to a roundl function call.
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
testRound(f128, 12.0);
|
||||
comptime try testRound(f128, 12.0);
|
||||
}
|
||||
|
||||
fn testRound(comptime T: type, x: T) !void {
|
||||
const y = x - 0.5;
|
||||
const z = @round(y);
|
||||
try expectEqual(x, z);
|
||||
try expect(x == z);
|
||||
}
|
||||
|
||||
test "vector integer addition" {
|
||||
@ -1225,10 +1303,15 @@ test "NaN comparison" {
|
||||
comptime try testNanEqNan(f32);
|
||||
comptime try testNanEqNan(f64);
|
||||
comptime try testNanEqNan(f128);
|
||||
}
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/11030
|
||||
// try testNanEqNan(f80);
|
||||
// comptime try testNanEqNan(f80);
|
||||
test "NaN comparison f80" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/11030
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
try testNanEqNan(f80);
|
||||
comptime try testNanEqNan(f80);
|
||||
}
|
||||
|
||||
fn testNanEqNan(comptime F: type) !void {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user